home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.pdx.edu / 2014.02.ftp.ee.pdx.edu.tar / ftp.ee.pdx.edu / pub / users / Harry / Blitz / version-1-0 / BlitzSrc / lddd.c < prev    next >
C/C++ Source or Header  |  2006-09-25  |  59KB  |  1,880 lines

  1. /* The BLITZ Linker
  2. **
  3. ** Copyright 2000-2006, Harry H. Porter III
  4. **
  5. ** This file may be freely copied, modified and compiled, on the sole
  6. ** conditions that if you modify it...
  7. **   (1) Your name and the date of modification is added to this comment
  8. **       under "Modifications by", and
  9. **   (2) Your name and the date of modification is added to the printHelp()
  10. **       routine under "Modifications by".
  11. **
  12. ** Original Author:
  13. **   12/29/00 - Harry H. Porter III
  14. **
  15. ** Modifcations by:
  16. **   03/15/06 - Harry H. Porter III
  17. **
  18. */
  19.  
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <stdarg.h>
  23. #include <string.h>
  24.  
  25.  
  26.  
  27. typedef struct FileInfo FileInfo;
  28. typedef struct RelocInfo RelocInfo;
  29. typedef struct TableEntry TableEntry;
  30. typedef struct LabelEntry LabelEntry;
  31.  
  32.  
  33.  
  34. /*****  Global variables *****/
  35.  
  36. int errorsDetected = 0;          /* The number of errors detected so far */
  37. int warningsDetected = 0;        /* The number of warnings detected so far */
  38. int commandOptionS = 0;          /* True: print the symbol table */
  39. int commandOptionL = 0;          /* True: print the listing */
  40. int pageSize = 8192;             /* Page Size (default = 8K) */
  41. int loadAddr = 0;                /* Addr at which program will be loaded */
  42. char * commandOutFileName = NULL;/* The a.out filename */
  43. FILE * inputFile;                /* The .o input file */
  44. FILE * outputFile;               /* The a.out output file */
  45. FileInfo * inputFileList;        /* Ptr to linked list of FileInfo's */
  46. int textStartAddr;               /* Starting addr of .text segment */
  47. int dataStartAddr;               /* Starting addr of .data segment */
  48. int bssStartAddr;                /* Starting addr of .bss segment */
  49. int totalTextSize;               /* Sum of all .text segment sizes */
  50. int totalDataSize;               /* Sum of all .data segment sizes */
  51. int totalBssSize;                /* Sum of all .bss segment sizes */
  52. char * textSegment;              /* All the bytes of the segment */
  53. char * dataSegment;              /* All the bytes of the segment */
  54. char * pmPtr;
  55. int pmSize;
  56. int pmCount;
  57. int pmRow[16];
  58. int numberOfEntries = 0;         /* Count of files containing _entry */
  59. TableEntry * absoluteEntry;      /* Ptr to table entry for .absolute */
  60.  
  61.  
  62.  
  63. /*****  FileInfo  *****
  64. **
  65. ** There is one of the following structures for each input .o file and
  66. ** they are kept in a linked list, headed by inputFileList.
  67. */
  68. struct FileInfo {
  69.   FileInfo *    next;
  70.   char *        filename;
  71.   FILE *        filePtr;
  72.   int           containsEntry;
  73.   int           sizeOfText;
  74.   int           sizeOfData;
  75.   int           sizeOfBss;
  76.   int           textAddr;
  77.   int           dataAddr;
  78.   int           bssAddr;
  79.   RelocInfo *   relocList;
  80. };
  81.  
  82.  
  83.  
  84. /*****  RelocInfo  *****
  85. **
  86. ** There is one of the following structures for each field that needs
  87. ** to be updated.  Each FileInfo contains a pointer to a linked list
  88. ** of these structures.
  89. */
  90. struct RelocInfo {
  91.   int           type;
  92.   int           locationToUpdate;
  93.   int           inText;
  94.   int           offset;
  95.   TableEntry *  relativeTo;
  96.   int           sourceLineNumber;
  97.   RelocInfo *   next;
  98. };
  99.  
  100.  
  101.  
  102. /*****  Symbol Table  *****
  103. **
  104. ** There is one of TableEntry structure for every symbol.  These structures
  105. ** are kept in a hash table.  The hash table itself is an array of pointer
  106. ** to linked lists of TableEntry structures, which are linked on "next".
  107. */
  108. struct TableEntry {
  109.   TableEntry * next;        /* Link list of TableEntry's */
  110.   char *       filename;    /* File in which this symbol occurs (for errors) */
  111.   int          value;       /* The value of this symbol */
  112.   int          relativeToS; /* The index of another symbol */
  113.   TableEntry * relativeToT; /* Ptr to the TableEntry for that symbol */
  114.   int          length;      /* The number of chars in the symbol */
  115.   char         string [0];  /* The characters in the symbol */
  116. };
  117.  
  118. #define SYMBOL_TABLE_HASH_SIZE 211    /* Size of hash table for sym table */
  119.  
  120. static TableEntry * symbolTableIndex [SYMBOL_TABLE_HASH_SIZE];
  121.  
  122. /* The following table maps symbol numbers to TableEntries.  It is
  123. ** filled once per input .o file, and re-used for each other file.
  124. ** In this table, certain numbers have meaning:
  125. **    0:    There is no entry in position 0; 0=imported
  126. **    1:    .text
  127. **    2:    .data
  128. **    3:    .bss
  129. **    4:    .absolute
  130. **    5...  (other entries, through maxSymbolNumber)
  131. */
  132.  
  133. #define MAX_NUMBER_OF_SYMBOLS 500000
  134.  
  135. TableEntry * tableArray [MAX_NUMBER_OF_SYMBOLS];
  136.  
  137. int maxSymbolNumber;       /* The index of the last valid entry. */
  138.  
  139.  
  140.  
  141. /*****  Label Table  *****
  142. **
  143. ** There is one of LabelEntry structure for every label.  These structures
  144. ** are kept in a hash table.  The hash table itself is an array of pointer
  145. ** to linked lists of LabelEntry structures, which are linked on "next".
  146. */
  147. struct LabelEntry {
  148.   LabelEntry * next;        /* Link list of LabelEntry's */
  149.   int          value;       /* The value of this label */
  150.   int          length;      /* The number of characters in the label */
  151.   char         string [0];  /* The characters in the label */
  152. };
  153.  
  154. #define LABEL_TABLE_HASH_SIZE 211    /* Size of hash table for label table */
  155.  
  156. static LabelEntry * labelTableIndex [LABEL_TABLE_HASH_SIZE];
  157.  
  158.  
  159.  
  160. /*****  Function prototypes  *****/
  161.  
  162. int main (int argc, char ** argv);
  163. void checkBigEndian ();
  164. void writeInteger (int i);
  165. void processCommandLine (int argc, char ** argv);
  166. void badOption (char * msg);
  167. void errorExit ();
  168. void printErrorAndExit (FileInfo * file, char * msg);
  169. void fatalError (char * msg);
  170. void printHelp ();
  171. int readInteger (FileInfo * file);
  172. int readByte (FileInfo * file);
  173. int roundUpToMultipleOf (int i, int p);
  174. void printMemory (char * ptr, int n);
  175. void get16Bytes ();
  176. int getNextByte ();
  177. void putlong (int i);
  178. void printline ();
  179. void printByte (int c);
  180. int bytesEqual (char * p, char * q, int lengthP, int lengthQ);
  181. void printSymbolTable ();
  182. void printSymbol (TableEntry *, int fieldWidth);
  183. void printSymbolOnFile (FILE * fp, TableEntry *, int fieldWidth);
  184. void printTableArray ();
  185. TableEntry * lookup (TableEntry * givenEntry);
  186. void resolveSymbols ();
  187. void performRelocations ();
  188. int get8 (char * ptr);
  189. int get16 (char * ptr);
  190. int get24 (char * ptr);
  191. int get32 (char * ptr);
  192. void put8 (char * ptr, int value);
  193. void put16 (char * ptr, int value);
  194. void put24 (char * ptr, int value);
  195. void put32 (char * ptr, int value);
  196. void printRelocationHeader ();
  197. void printRelocationRecord (RelocInfo * rel);
  198. void readRelocationRecords (FileInfo * file);
  199. void addLabels ();
  200. int lookupLabel (LabelEntry * newEntry);
  201. void writeLabels ();
  202.  
  203.  
  204.  
  205. /* main()
  206. **
  207. ** Read through all input files and produce the output file.
  208. */
  209. main (int argc, char ** argv) {
  210.     FileInfo * inFile, * fileWithEntry;
  211.     int magic, i, j, unpaddedTextSize, unpaddedDataSize;
  212.     int nextText, nextData, nextBss, inText;
  213.     char * targetAddr, *q;
  214.     int symbolNum, value, relativeToS, len;
  215.     TableEntry * entryPtr, * existingEntry;
  216.     RelocInfo * rel;
  217.  
  218.     inputFileList = NULL;
  219.     checkBigEndian ();
  220.     processCommandLine (argc, argv);
  221.     totalTextSize = 0;
  222.     totalDataSize = 0;
  223.     totalBssSize = 0;
  224.     if (commandOptionL) {
  225.       printf ("==========  Computing Segment Sizes  ==========\n");
  226.       printf (" pageSize = %08x (%d)\n", pageSize, pageSize);
  227.       printf (" loadAddr = %08x (%d)\n", loadAddr, loadAddr);
  228.     }
  229.  
  230.     /* Each execution of this loop reads from the next .o file. */
  231.     if (commandOptionL) {
  232.       printf (" Scanning files to pickup chunk sizes...\n");
  233.     }
  234.     for (inFile=inputFileList;
  235.          inFile!=NULL;
  236.          inFile=inFile->next) {
  237.       magic = readInteger (inFile);
  238.       if (magic != 0x424C5A6F) {   /* "BLZo" in hex */
  239.         printErrorAndExit (inFile,
  240.            "File is not a .o file (magic number is incorrect)");
  241.       }
  242.       /* Pick up the header info and add it to this FileInfo record. */
  243.       inFile->containsEntry = readInteger (inFile);
  244.       if (inFile->containsEntry == 0) {
  245.       } else if (inFile->containsEntry == 1) {
  246.         numberOfEntries++;
  247.         fileWithEntry = inFile;
  248.       } else {
  249.         printErrorAndExit (inFile, "ContainsEntry is incorrect");
  250.       }
  251.       inFile->sizeOfText = readInteger (inFile);
  252.       inFile->sizeOfData = readInteger (inFile);
  253.       inFile->sizeOfBss = readInteger (inFile);
  254.       /* Add these .text, .data, and .bss chunk sizes to the totals. */
  255.       totalTextSize += roundUpToMultipleOf (inFile->sizeOfText, 4);
  256.       totalDataSize += roundUpToMultipleOf (inFile->sizeOfData, 4);
  257.       totalBssSize += roundUpToMultipleOf (inFile->sizeOfBss, 4);
  258.     }
  259.  
  260.     /* Check that only one file contains "_entry". */
  261.     if (numberOfEntries < 1) {
  262.       fatalError ("No input file contains \"_entry\"");
  263.     } else if (numberOfEntries > 1) {
  264.       fatalError ("More than one input file contains \"_entry\"");
  265.     }
  266.     /* If that file is not already at the head of the list, put it there. */
  267.     if (inputFileList != fileWithEntry) {
  268.       for (inFile=inputFileList;
  269.            inFile->next != fileWithEntry;
  270.            inFile=inFile->next) {
  271.       }
  272.       inFile->next = inFile->next->next;
  273.       fileWithEntry->next = inputFileList;
  274.       inputFileList = fileWithEntry;
  275.     }
  276.  
  277.     /* Compute the sizes of the segments. */
  278.     if (commandOptionL) {
  279.       printf (" Computing sizes of the segments...\n");
  280.       printf ("  totalTextSize = %08x (%d)\n", totalTextSize, totalTextSize);
  281.       printf ("  totalDataSize = %08x (%d)\n", totalDataSize, totalDataSize);
  282.       printf ("  totalBssSize =  %08x (%d)\n", totalBssSize,  totalBssSize);
  283.       printf (" Rounding segments up to a multiple of pageSize...\n");
  284.     }
  285.     unpaddedTextSize = totalTextSize;
  286.     unpaddedDataSize = totalDataSize;
  287.     totalTextSize = roundUpToMultipleOf (totalTextSize, pageSize);
  288.     totalDataSize = roundUpToMultipleOf (totalDataSize, pageSize);
  289.     totalBssSize = roundUpToMultipleOf (totalBssSize, pageSize);
  290.     if (commandOptionL) {
  291.       printf ("  totalTextSize = %08x (%d)\n", totalTextSize, totalTextSize);
  292.       printf ("  totalDataSize = %08x (%d)\n", totalDataSize, totalDataSize);
  293.       printf ("  totalBssSize =  %08x (%d)\n", totalBssSize,  totalBssSize);
  294.     }
  295.     i = totalTextSize + totalDataSize + totalBssSize;
  296.     if ((i < 0) || (i > 16777216)) {
  297.       warningsDetected++;
  298.       fprintf (stderr,
  299.         "BLITZ Linker Warning: The size of .text, .data, and .bss (0x%08x) exceeds 16MB limit.\n",
  300.         i);
  301.     }
  302.  
  303.     /* Allocate memory chunks to hold the .text and .data segments. */
  304.     if (commandOptionL) {
  305.       printf (" Allocating memory for text and data segments...\n");
  306.     }
  307.     textSegment = (char *) calloc (totalTextSize, 1);
  308.     dataSegment = (char *) calloc (totalDataSize, 1);
  309.     if ((textSegment == NULL) || (dataSegment == NULL)) {
  310.       fatalError ("Calloc failed - insufficient memory available");
  311.     }
  312.     if (commandOptionL) {
  313.       printf ("  Memory addr of text segment = %08x (%d)\n",
  314.                                            textSegment, textSegment);
  315.       printf ("  Memory addr of data segment = %08x (%d)\n",
  316.                                            dataSegment, dataSegment);
  317.     }
  318.  
  319.     /* Compute the starting addresses of the segments. */
  320.     if (commandOptionL) {
  321.       printf (" Computing starting addresses ...\n");
  322.     }
  323.     textStartAddr = loadAddr;
  324.     dataStartAddr = textStartAddr + totalTextSize;
  325.     bssStartAddr = dataStartAddr + totalDataSize;
  326.     if (commandOptionL) {
  327.       printf ("  textStartAddr = %08x (%d)\n", textStartAddr, textStartAddr);
  328.       printf ("  dataStartAddr = %08x (%d)\n", dataStartAddr, dataStartAddr);
  329.       printf ("  bssStartAddr  = %08x (%d)\n\n", bssStartAddr, bssStartAddr);
  330.     }
  331.     nextText = textStartAddr;
  332.     nextData = dataStartAddr;
  333.     nextBss = bssStartAddr;
  334.     
  335.     /* Run through each file again. */
  336.     for (inFile=inputFileList;
  337.          inFile!=NULL;
  338.          inFile=inFile->next) {
  339.       if (commandOptionL) {
  340.         printf ("==========  Processing file %s  ==========\n",
  341.                                                      inFile->filename);
  342.         printf (" contains entry = %d\n", inFile->containsEntry);
  343.       }
  344.  
  345.       /* Compute the memory location for this .text, .data, and .bss chunk. */
  346.       inFile->textAddr = nextText;
  347.       inFile->dataAddr = nextData;
  348.       inFile->bssAddr = nextBss;
  349.       nextText += roundUpToMultipleOf (inFile->sizeOfText, 4);
  350.       nextData += roundUpToMultipleOf (inFile->sizeOfData, 4);
  351.       nextBss += roundUpToMultipleOf (inFile->sizeOfBss, 4);
  352.       if (commandOptionL) {
  353.         printf (" textAddr       = %08x (%d)\n", inFile->textAddr,
  354.                                                  inFile->textAddr);
  355.         printf (" dataAddr       = %08x (%d)\n", inFile->dataAddr,
  356.                                                  inFile->dataAddr);
  357.         printf (" bssAddr        = %08x (%d)\n", inFile->bssAddr,
  358.                                                  inFile->bssAddr);
  359.         printf (" size of text   = %08x (%d)\n", inFile->sizeOfText,
  360.                                                  inFile->sizeOfText);
  361.         printf (" size of data   = %08x (%d)\n", inFile->sizeOfData,
  362.                                                  inFile->sizeOfData);
  363.         printf (" size of bss    = %08x (%d)\n", inFile->sizeOfBss,
  364.                                                  inFile->sizeOfBss);
  365.       }
  366.  
  367.       /* Move this .text chunk into the right spot in the in-memory segment. */
  368.       if (commandOptionL) {
  369.         printf (" Reading text chunk into memory...\n");
  370.       }
  371.       /***  printMemory (textSegment, unpaddedTextSize);  ***/
  372.       targetAddr = textSegment + (inFile->textAddr - textStartAddr);
  373.       i = fread (targetAddr, 1, inFile->sizeOfText, inFile->filePtr);
  374.       if (commandOptionL) {
  375.         printf ("    memory addr = %08x (%d)\n", targetAddr, targetAddr);
  376.         printf ("    bytes read  = %08x (%d)\n", i, i);
  377.       }
  378.       if (i != inFile->sizeOfText) {
  379.         printErrorAndExit (inFile,
  380.                            "Problems reading text segment from .o file");
  381.       }
  382.       magic = readInteger (inFile);
  383.       if (magic != 0x2a2a2a2a) {
  384.         printErrorAndExit (inFile, "Invalid **** separator");
  385.       }
  386.       /***  printMemory (textSegment, unpaddedTextSize);  ***/
  387.  
  388.       /* Move this data chunk into the right spot in the in-memory segment. */
  389.       if (commandOptionL) {
  390.         printf (" Reading data chunk into memory...\n");
  391.       }
  392.       /***  printMemory (dataSegment, unpaddedDataSize);  ***/
  393.       targetAddr = dataSegment + (inFile->dataAddr - dataStartAddr);
  394.       i = fread (targetAddr, 1, inFile->sizeOfData, inFile->filePtr);
  395.       if (commandOptionL) {
  396.         printf ("    memory addr = %08x (%d)\n", targetAddr, targetAddr);
  397.         printf ("    bytes read  = %08x (%d)\n", i, i);
  398.       }
  399.       if (i != inFile->sizeOfData) {
  400.         printErrorAndExit (inFile,
  401.                            "Problems reading data segment from .o file");
  402.       }
  403.       magic = readInteger (inFile);
  404.       if (magic != 0x2a2a2a2a) {
  405.         printErrorAndExit (inFile, "Invalid **** separator");
  406.       }
  407.       /***  printMemory (dataSegment, unpaddedDataSize);  ***/
  408.  
  409.       /* Run through the symbols in this .o file.  Each iteration reads
  410.          in one symbol and processes it. */
  411.       maxSymbolNumber = 0;
  412.       while (1) {
  413.  
  414.         /* Read in symbolNumber, value, relativeTo, and length. */
  415.         symbolNum = readInteger (inFile);
  416.         if (symbolNum == 0) break;
  417.         maxSymbolNumber++;
  418.         if (maxSymbolNumber >= MAX_NUMBER_OF_SYMBOLS) {
  419.           printErrorAndExit (inFile, "The linker can handle only a limited number of symbols and this file has more than that");
  420.         }
  421.         if (maxSymbolNumber != symbolNum) {
  422.           printErrorAndExit (inFile, "Invalid symbol number");
  423.         }
  424.         value = readInteger (inFile);
  425.         relativeToS = readInteger (inFile);
  426.         len = readInteger (inFile);
  427.  
  428.         /* Create a TableEntry and initialize it. */
  429.         entryPtr = (TableEntry *) calloc (1, sizeof (TableEntry) + len + 1);
  430.         if (entryPtr == 0) {
  431.           fatalError ("Calloc failed - insufficient memory available");
  432.         }
  433.         tableArray [symbolNum] = entryPtr;
  434.         entryPtr->length = len;
  435.         entryPtr->value = value;
  436.         entryPtr->relativeToS = relativeToS;
  437.         entryPtr->relativeToT = NULL;
  438.         entryPtr->filename = inFile->filename;
  439.  
  440.         /* Read in the characters and move into this TableEntry. */
  441.         /*** printf ("Processing "); ***/
  442.         for (q=entryPtr->string, j=len;
  443.              j>0;
  444.              q++, j--) {
  445.           *q = readByte (inFile);
  446.           /*** printf ("%c", *q); ***/
  447.         }
  448.         /*** printf ("...  "); ***/
  449.  
  450.         /* Look this string up in the symbol table. */
  451.         existingEntry = lookup (entryPtr);
  452.         if (existingEntry == NULL) {    /* if not found... */
  453.           /* ...then it will have gotten added to the symbol table. */
  454.           /*** printf ("Not found.  It was added.\n"); ***/
  455.           /* Fill in values for .text, .data, .bss; save ptr to .absolute. */
  456.           if (symbolNum == 1) {
  457.             entryPtr->value = textStartAddr;
  458.             entryPtr->relativeToS = 4;
  459.           } else if (symbolNum == 2) {
  460.             entryPtr->value = dataStartAddr;
  461.             entryPtr->relativeToS = 4;
  462.           } else if (symbolNum == 3) {
  463.             entryPtr->value = bssStartAddr;
  464.             entryPtr->relativeToS = 4;
  465.           } else if (symbolNum == 4) {
  466.             absoluteEntry = entryPtr;
  467.           }
  468.  
  469.         /* If found in the table... */
  470.         } else {
  471.           /*** printf ("Found.\n"); ***/
  472.           /* Fill in values for .text, .data, .bss; and ignore .absolute. */
  473.           if (symbolNum == 1) {
  474.             entryPtr->value = inFile->textAddr;
  475.             entryPtr->relativeToS = 4;
  476.           } else if (symbolNum == 2) {
  477.             entryPtr->value = inFile->dataAddr;
  478.             entryPtr->relativeToS = 4;
  479.           } else if (symbolNum == 3) {
  480.             entryPtr->value = inFile->bssAddr;
  481.             entryPtr->relativeToS = 4;
  482.           } else if (symbolNum == 4) {
  483.           } else {  /* i.e., for all other symbols... */
  484.             /* If existing was imported, grab value from new. */
  485.             if (existingEntry->relativeToT == NULL) {
  486.               /*** printf ("  Existing entry is imported.\n"); ***/
  487.               existingEntry->value = entryPtr->value;
  488.               existingEntry->relativeToS = entryPtr->relativeToS;
  489.             } else {
  490.               /*** printf ("  Existing entry has a value.\n"); ***/
  491.               /* If the new entry is also not imported, it is an error. */
  492.               if (entryPtr->relativeToS != 0) {
  493.                 fprintf (stderr, "BLITZ Linker Error: The symbol \"");
  494.                 printSymbolOnFile (stderr, entryPtr, 1);
  495.                 fprintf (stderr,
  496.                          "\" is defined and exported from more than one file, including file \"%s\"\n",
  497.                          inFile->filename);
  498.                 errorsDetected++;
  499.               }
  500.             }
  501.             /* From now on use the existing entry. */
  502.             tableArray [symbolNum] = existingEntry;
  503.           }
  504.         }
  505.       }
  506.  
  507.       /* Read in the magic number after the symbols. */
  508.       magic = readInteger (inFile);
  509.       if (magic != 0x2a2a2a2a) {   /* "****" in hex */
  510.         printErrorAndExit (inFile, "Invalid **** separator");
  511.       }
  512.  
  513.       /*** printTableArray (); ***/
  514.       fflush (stdout);
  515.  
  516.       /* Run through the new chunk's symbols.  In the .o file, each symbol's
  517.          relativeTo specified another symbol by number.  (This integer was
  518.          stored in the "relativeToS" field in the TableEntry.  Each iteration
  519.          of this loop will set the relativeTo field (or, more precisely, the
  520.          "relativeToT" field) of the symbol to point directly the TableEntry
  521.          of the other symbol.  */
  522.       if (commandOptionL) {
  523.         printf (" Processing this file's symbols...\n");
  524.       }
  525.       for (i=1; i<=maxSymbolNumber; i++) {
  526.         entryPtr = tableArray [i];
  527.         j = entryPtr->relativeToS;
  528.         if (j<=0) {
  529.         } else if (j<=3) {
  530.           entryPtr->value += tableArray[j] -> value;
  531.           entryPtr->relativeToT = absoluteEntry;
  532.           entryPtr->relativeToS = 4;
  533.         } else if (j==4) {
  534.           entryPtr->relativeToT = absoluteEntry;
  535.         } else {
  536.           entryPtr->relativeToT = tableArray [j];
  537.           entryPtr->relativeToS = 0;
  538.         }
  539.       }
  540.  
  541.       /*** printTableArray (); ***/
  542.  
  543.       /* Read in all the relocation records for this file and add each
  544.          to the linked list of RelocInfo structs for this FileInfo. */
  545.       readRelocationRecords (inFile);
  546.  
  547.       /* Read in the magic number after the relocation records. */
  548.       magic = readInteger (inFile);
  549.       if (magic != 0x2a2a2a2a) {   /* "****" in hex */
  550.         printErrorAndExit (inFile, "Invalid **** separator");
  551.       }
  552.  
  553.       /* Run through this file's relocation records and print them. */
  554.       if (commandOptionL) {
  555.         printf ("    Here are the relocation records...\n");
  556.         printRelocationHeader ();
  557.         for (rel=inFile->relocList; rel!=NULL; rel=rel->next) {
  558.           printRelocationRecord (rel);
  559.         }
  560.         printf ("\n");
  561.       }
  562.  
  563.       /* Done with this file */
  564.  
  565.     }
  566.     /* Done with all files. */
  567.  
  568.     /* Print the symbol table, if "-l" option was used. */
  569.     if (commandOptionL) {
  570.       printSymbolTable ();
  571.       printf ("\n");
  572.     }
  573.  
  574.     /* Run through each symbol in the symbol table; compute and fill in
  575.        its absolute value. */
  576.     if (commandOptionL) {
  577.       printf ("Resolving symbols...\n");
  578.     }
  579.     resolveSymbols ();
  580.  
  581.     /* Print the symbol table again, the time if "-s" option was used. */
  582.     if (commandOptionS) {
  583.       printf ("\n");
  584.       printSymbolTable ();
  585.       printf ("\n");
  586.     }
  587.  
  588.     /* Perform the relocations */
  589.     if (commandOptionL) {
  590.       printf ("Performing the relocations...\n");
  591.     }
  592.     performRelocations ();
  593.  
  594.     /* Run through the files again and add the labels to the label table. */
  595.     if (commandOptionL) {
  596.       printf ("Processing Labels...\n");
  597.     }
  598.     addLabels ();
  599.  
  600.     if (errorsDetected) {
  601.       fprintf (stderr, "BLITZ Linker: %d errors were detected!\n",
  602.                                                          errorsDetected);
  603.       if (commandOptionL) {
  604.         printf ("%d warnings were detected.\n", warningsDetected);
  605.         printf ("%d errors were detected.\n", errorsDetected);
  606.       }
  607.       errorExit ();
  608.     }
  609.  
  610.     /* Write the magic number to the a.out file. */
  611.     writeInteger (0x424C5A78);   /* "BLZx" as an integer */
  612.  
  613.     /* Write header info. */
  614.     writeInteger (totalTextSize);
  615.     writeInteger (totalDataSize);
  616.     writeInteger (totalBssSize);
  617.     writeInteger (textStartAddr);
  618.     writeInteger (dataStartAddr);
  619.     writeInteger (bssStartAddr);
  620.     writeInteger (0x02a2a2a2a);   /* "****" as an integer */
  621.  
  622.     /* Write out the .text segment. */
  623.     i = fwrite (textSegment, 1, totalTextSize, outputFile);
  624.     if (i != totalTextSize) {
  625.       fatalError ("Error while writing to output executable file");
  626.     }
  627.     writeInteger (0x02a2a2a2a);   /* "****" as an integer */
  628.  
  629.     /* Write out the .data segment. */
  630.     i = fwrite (dataSegment, 1, totalDataSize, outputFile);
  631.     if (i != totalDataSize) {
  632.       fatalError ("Error while writing to output executable file");
  633.     }
  634.     writeInteger (0x02a2a2a2a);   /* "****" as an integer */
  635.  
  636.     /* Write the Label info out to the a.out file. */
  637.     writeLabels ();
  638.     writeInteger (0x02a2a2a2a);   /* "****" as an integer */
  639.  
  640.     if (warningsDetected) {
  641.       fprintf (stderr, "BLITZ Linker: %d warnings were issued!\n",
  642.                                                       warningsDetected);
  643.     }
  644.     if (errorsDetected) {
  645.       fprintf (stderr, "BLITZ Linker: %d errors were detected!\n",
  646.                                                       errorsDetected);
  647.       errorExit ();
  648.     }
  649.     if (commandOptionL) {
  650.       printf ("%d warnings were detected.\n", warningsDetected);
  651.       printf ("%d errors were detected.\n", errorsDetected);
  652.     }
  653.     exit (0);
  654. }
  655.  
  656.  
  657.  
  658. /* checkBigEndian ()
  659. **
  660. ** This routine checks to make sure the machine running this
  661. ** program uses big-endian byte ordering and aborts if not.
  662. */
  663. void checkBigEndian () {
  664.   union fourBytes {
  665.     char chars [4];
  666.     unsigned int i;
  667.   } fourBytes;
  668.   fourBytes.chars[0] = 0x12;
  669.   fourBytes.chars[1] = 0x34;
  670.   fourBytes.chars[2] = 0x56;
  671.   fourBytes.chars[3] = 0x78;
  672.   if (fourBytes.i != 0x12345678) {
  673.     fatalError ("This program only runs on big-endian computers");
  674.   }
  675. }
  676.  
  677.  
  678.  
  679. /* writeInteger (i)
  680. **
  681. ** This routine writes out 4 bytes to the .o file.
  682. */
  683. void writeInteger (int i) {
  684.   fwrite (&i, 4, 1, outputFile);
  685. }
  686.  
  687.  
  688.  
  689. /* processCommandLine (argc, argv)
  690. **
  691. ** This routine processes the command line options.
  692. */
  693. void processCommandLine (int argc, char ** argv) {
  694.   int argCount;
  695.   int len;
  696.   int gotLoadAddr = 0;
  697.   int gotPageSize = 0;
  698.   FileInfo * p, * q;
  699.  
  700.   /* Each iteration of this loop looks at the next argument.  In some
  701.      cases (like "-o a.out") one iteration will scan two tokens. */
  702.   for (argc--, argv++; argc > 0; argc -= argCount, argv += argCount) {
  703.     argCount = 1;
  704.     /* Scan the -h option */
  705.     if (!strcmp (*argv, "-h")) {
  706.       printHelp ();
  707.       exit (1);
  708.     /* Scan the -s option */
  709.     } else if (!strcmp (*argv, "-s")) {
  710.       commandOptionS = 1;
  711.     /* Scan the -l option */
  712.     } else if (!strcmp (*argv, "-l")) {
  713.       commandOptionL = 1;
  714.     /* Scan the -p option */
  715.     } else if (!strcmp (*argv, "-p")) {
  716.       gotPageSize = 1;
  717.       if (argc <= 1) {
  718.         badOption ("Expecting integer after -p option");
  719.       } else {
  720.         argCount++;
  721.         pageSize = atoi (*(argv+1));  /* Extra chars after int are ignored */
  722.         if ((pageSize <= 0) || (pageSize % 4 != 0)) {
  723.           badOption ("Invalid integer after -p option");
  724.         }
  725.       }
  726.     /* Scan the -a option */
  727.     } else if (!strcmp (*argv, "-a")) {
  728.       gotLoadAddr = 1;
  729.       if (argc <= 1) {
  730.         badOption ("Expecting integer after -a option");
  731.       } else {
  732.         argCount++;
  733.         loadAddr = atoi (*(argv+1));  /* Extra chars after int are ignored */
  734.         if (loadAddr < 0) {
  735.           badOption ("Invalid integer after -a option");
  736.         }
  737.       }
  738.     /* Scan the -o option, which should be followed by a file name */
  739.     } else if (!strcmp (*argv, "-o")) {
  740.       if (argc <= 1) {
  741.         badOption ("Expecting filename after -o option");
  742.       } else {
  743.         argCount++;
  744.         if (commandOutFileName == NULL) {
  745.           commandOutFileName = *(argv+1);
  746.         } else {
  747.           badOption ("Invalid command line - multiple output files");
  748.         }
  749.       }
  750.     /* Deal with any invalid options that begin with "-", such as "-qwerty" */
  751.     } else if ((*argv)[0] == '-') {
  752.       fprintf (
  753.         stderr,
  754.         "BLITZ Linker Error: Invalid command line option (%s); Use -h for help display\n",
  755.         *argv);
  756.       exit (1);
  757.     /* This token will be interpreted as an input file name. */
  758.     } else {
  759.       /* Create a FileInfo and chain it into the linked list. */
  760.       p = (FileInfo *) calloc (1, sizeof (FileInfo));
  761.       if (p == NULL) {
  762.         fprintf (stderr, "BLITZ Linker Error: Calloc failed - insufficient memory available.\n");
  763.         exit (1);
  764.       }
  765.       p->filename = *argv;
  766.       /* Open this .o file for reading. */
  767.       p->filePtr = fopen (p->filename, "r");
  768.       if (p->filePtr == NULL) {
  769.         fprintf (stderr,
  770.                  "BLITZ Linker Error: Input file \"%s\" could not be opened\n",
  771.                  p->filename);
  772.         exit (1);
  773.       }
  774.       p->next = inputFileList;
  775.       inputFileList = p;
  776.     }
  777.   }
  778.  
  779.   /* If there were no input files, then abort. */
  780.   if (inputFileList == NULL) {
  781.     badOption ("There must be at least one .o input file");
  782.   }
  783.  
  784.   /* Make sure the starting address is a multiple of the pageSize */
  785.   if (loadAddr % pageSize != 0) {
  786.     badOption ("The load address must be a multiple of the page size");
  787.   }
  788.  
  789.   /* The list of input file is in reverse order.  Reverse it back. */
  790.   q = inputFileList;
  791.   inputFileList = NULL;
  792.   while (q != NULL) {
  793.     p = q;
  794.     q = q->next;
  795.     p->next = inputFileList;
  796.     inputFileList = p;
  797.   }
  798.  
  799.   /* Figure out the name of the a.out file. */
  800.   if (commandOutFileName == NULL) {
  801.     commandOutFileName = "a.out";
  802.   }
  803.  
  804.   /* Open the output (a.out) file. */
  805.   outputFile = fopen (commandOutFileName, "wa");
  806.   if (outputFile == NULL) {
  807.     fprintf (stderr,
  808.              "BLITZ Linker Error: Output file \"%s\" could not be opened\n",
  809.              commandOutFileName);
  810.     exit (1);
  811.   }
  812. }
  813.  
  814.  
  815.  
  816. /* badOption (msg)
  817. **
  818. ** This routine prints a message on stderr and then aborts this program.
  819. */
  820. void badOption (char * msg) {
  821.   fprintf (stderr, "BLITZ Linker Error: %s;  Use -h for help display\n", msg);
  822.   exit (1);
  823. }
  824.  
  825.  
  826.  
  827. /* printErrorAndExit (file, str)
  828. **
  829. ** This routine prints a message of the form:
  830. **    Problem with file "xxx.o": yyy
  831. ** It then calls errorExit() to abort.
  832. */
  833. void printErrorAndExit (FileInfo * file, char * msg) {
  834.   fprintf (stderr,
  835.            "BLITZ Linker Error: Problem with file \"%s\"; %s\n",
  836.            file->filename, msg);
  837.   errorExit ();
  838. }
  839.  
  840.  
  841.  
  842. /* fatalError (msg)
  843. **
  844. ** This routine prints the given error message on stderr and calls errorExit().
  845. */
  846. void fatalError (char * msg) {
  847.   fprintf (stderr, "BLITZ Linker Error: %s\n", msg);
  848.   errorExit ();
  849. }
  850.  
  851.  
  852.  
  853. /* errorExit ()
  854. **
  855. ** This routine removes the output (a.out) file and calls exit(1).
  856. */
  857. void errorExit () {
  858.   remove (commandOutFileName);
  859.   exit (1);
  860. }
  861.  
  862.  
  863.  
  864. /* printHelp ()
  865. **
  866. ** This routine prints some documentation.  It is invoked whenever
  867. ** the -h option is used on the command line.
  868. */
  869. void printHelp () {
  870.   printf (
  871. "==============================\n"
  872. "=====                    =====\n"
  873. "=====  The BLITZ Linker  =====\n"
  874. "=====                    =====\n"
  875. "==============================\n"
  876. "\n"
  877. "Copyright 2000-2006, Harry H. Porter III\n"
  878. "========================================\n"
  879. "  Original Author:\n"
  880. "    12/29/00 - Harry H. Porter III\n"
  881. "  Modifcations by:\n"
  882. "    03/15/06 - Harry H. Porter III\n"
  883. "\n"
  884. "Command Line Options\n"
  885. "====================\n"
  886. "  These command line options may be given in any order.\n"
  887. "    filename1 filename2 filename3 ...\n"
  888. "       The input object files, which will normally end with \".o\".\n"
  889. "       There must be at least one input file.\n"
  890. "    -h\n"
  891. "       Print this help info.  Ignore other options and exit.\n"
  892. "    -o filename\n"
  893. "       If there are no errors, an executable file will be created.  This\n"
  894. "       option can be used to give the object file a specific name.\n"
  895. "       If this option is not used, then the output file will be named\n"
  896. "       \"a.out\".\n"
  897. "    -l\n"
  898. "       Print a listing on stdout.\n"
  899. "    -s\n"
  900. "       Print the symbol table on stdout.\n"
  901. "    -p integer\n"
  902. "       The page size.  The integer must be a multiple of 4 greater than\n"
  903. "       zero.  (The default is 8192 = 8K.)\n"
  904. "    -a integer\n"
  905. "       The logical address at which to load the program at run-time.\n"
  906. "       The integer must be a non-negative multiple of the page size.\n"
  907. "       (The default is 0.)\n");
  908. }
  909.  
  910.  
  911.  
  912. /* readInteger (file)
  913. **
  914. ** Read a integer (4-bytes, binary) from one of the .o files and return it.
  915. */
  916. int readInteger (FileInfo * file) {
  917.   int i, numItemsRead;
  918.   numItemsRead = fread (&i, 4, 1, file->filePtr);
  919.   if (numItemsRead != 1) {
  920.     printErrorAndExit (file, "Problem reading from object file");
  921.   }
  922.   return i;
  923. }
  924.  
  925.  
  926.  
  927. /* readByte (file)
  928. **
  929. ** Read 1 byte from one of the .o files and return it as an integer.
  930. */
  931. int readByte (FileInfo * file) {
  932.   int i, numBytesRead;
  933.   char c;
  934.   numBytesRead = fread (&c, 1, 1, file->filePtr);
  935.   if (numBytesRead != 1) {
  936.     printErrorAndExit (file, "Problem reading from object file");
  937.   }
  938.   i = c;
  939.   return i;
  940. }
  941.  
  942.  
  943.  
  944. /* roundUpToMultipleOf (i, p)
  945. **
  946. ** This routine rounds i up to a multiple of p and returns the result.
  947. */
  948. int roundUpToMultipleOf (int i, int p) {
  949.   if ((i < 0) || (p <= 0)) {
  950.     fatalError ("PROGRAM LOGIC ERROR - Bad arg in roundUpToMultipleOf()");
  951.   }
  952.   if (i % p > 0) {
  953.     return (i / p + 1) * p;
  954.   }
  955.   return i;
  956. }
  957.  
  958.  
  959.  
  960. /* printMemory (ptr, n)
  961. **
  962. ** This routine dumps n bytes of memory (located at "ptr") in hex.
  963. */
  964. void printMemory (char * ptr, int n) {
  965.    int addr;
  966.    pmCount = n;
  967.    pmPtr = ptr;
  968.    addr = (int) ptr;
  969.  
  970.    /* Each execution of this loop prints a single output line. */
  971.    get16Bytes ();
  972.    while (pmSize > 0) {
  973.      putlong (addr);
  974.      printf (":  ");
  975.      printline ();
  976.      addr = addr + 16;
  977.      get16Bytes ();
  978.    }
  979.  
  980. }
  981.  
  982.  
  983.  
  984. /* get16Bytes ()
  985. **
  986. ** This routine reads in the next 16 bytes from memory and
  987. ** places them in the array named "pmRow", setting "pmSize" to
  988. ** be the number of bytes moved.  "pmSize" will be less than
  989. ** 16 if EOF was encountered, and may possibly be 0.
  990. */
  991. void get16Bytes () {
  992.   int c;
  993.   pmSize = 0;
  994.   c = getNextByte ();
  995.   while (c != -999) {
  996.     pmRow [pmSize++] = c;
  997.     if (pmSize >= 16) break;
  998.     c = getNextByte ();
  999.   }
  1000. }
  1001.  
  1002.  
  1003.  
  1004. /* getNextByte () 
  1005. **
  1006. ** Get the next byte from memory, from the location pointed to by
  1007. ** "pmPtr", incrementing "pmPtr" and decrementing the counter "pmCount."
  1008. ** This routine will return it as an integer, or return -999 if pmCount <= 0.
  1009. */
  1010. int getNextByte () {
  1011.   if (pmCount <= 0) return -999;
  1012.   pmCount--;
  1013.   return *(pmPtr++);
  1014. }
  1015.  
  1016.  
  1017.  
  1018. /* putlong (i)
  1019. **
  1020. ** This routine is passed an integer, which it prints as 8 hex digits.
  1021. */
  1022. void putlong (int i) {
  1023.   printByte ((i>>24) & 0x000000ff);
  1024.   printByte ((i>>16) & 0x000000ff);
  1025.   printByte ((i>>8) & 0x000000ff);
  1026.   printByte ((i>>0) & 0x000000ff);
  1027. }
  1028.  
  1029.  
  1030.  
  1031. /* printline ()
  1032. **
  1033. ** This routine prints the current 'pmRow'.
  1034. */
  1035. void printline () {
  1036.   int i, c;
  1037.   if (pmSize > 0) {
  1038.     i = 0;
  1039.     while (i<16) {
  1040.       if (i < pmSize) {
  1041.         printByte (pmRow[i]);
  1042.       } else {
  1043.         printf ("  ");
  1044.       }
  1045.       i++;
  1046.       if ((i%2) == 0) {
  1047.         putchar (' ');
  1048.       }
  1049.       if ((i%4) == 0) {
  1050.         putchar (' ');
  1051.       }
  1052.     }
  1053.     printf ("  ");
  1054.     for (i=0; i<pmSize; i++) {
  1055.       c = pmRow[i];
  1056.       if ((c>=' ') && (c <= '~')) {
  1057.         putchar (c);
  1058.       } else {
  1059.         putchar ('.');
  1060.       }
  1061.     }
  1062.     printf ("\n");
  1063.   }
  1064. }
  1065.  
  1066.  
  1067.  
  1068. /* printByte (c)
  1069. **
  1070. ** This routine is passed a byte (i.e., an integer -128..255) which
  1071. ** it prints as 2 hex characters.  If passed a number out of that
  1072. ** range, it outputs nothing.
  1073. */
  1074. void printByte (int c) {
  1075.   int i;
  1076.   if (c<0) c = c + 256;
  1077.   if ((c >= 0) && (c <= 255)) {
  1078.     i = (c & 0x000000f0) >> 4;
  1079.     if (i < 10) {
  1080.       putchar ('0' + i);
  1081.     } else {
  1082.       putchar ('A' + i - 10);
  1083.     }
  1084.     i = (c & 0x0000000f) >> 0;
  1085.     if (i < 10) {
  1086.       putchar ('0' + i);
  1087.     } else {
  1088.       putchar ('A' + i - 10);
  1089.     }
  1090.   }
  1091. }
  1092.  
  1093.  
  1094.  
  1095. /* bytesEqual (p, q, lengthP, lengthQ)
  1096. **
  1097. ** This function is passed two pointers to blocks of bytes, and a
  1098. ** length.  It compares the two sequences of bytes and returns true iff
  1099. ** they are both equal.
  1100. */
  1101. int bytesEqual (char * p, char * q, int lengthP, int lengthQ) {
  1102.   if (lengthP != lengthQ) return 0;
  1103.   for (; lengthP>0; lengthP--, p++, q++) {
  1104.     if (*p != *q) return 0;
  1105.   }
  1106.   return 1;
  1107. }
  1108.  
  1109.  
  1110.  
  1111. /* printSymbolTable ()
  1112. **
  1113. ** This routine runs through the symbol table and prints each entry.
  1114. */
  1115. void printSymbolTable () {
  1116.   int hashVal;
  1117.   TableEntry * entryPtr;
  1118.   printf ("SYMBOL                                   VALUE     (decimal) RELATIVE-TO\n");
  1119.   printf ("======================================== =================== ===========\n");
  1120.   for (hashVal = 0; hashVal<SYMBOL_TABLE_HASH_SIZE; hashVal++) {
  1121.     for (entryPtr = symbolTableIndex [hashVal];
  1122.                        entryPtr;
  1123.                        entryPtr = entryPtr->next) {
  1124.       printSymbol (entryPtr, 40);
  1125.       printf (" %08x", entryPtr->value);
  1126.       printf ("%11d", entryPtr->value);
  1127.       printf (" %d  ", entryPtr->relativeToS);
  1128.       if (entryPtr->relativeToT != NULL) {
  1129.         printSymbol (entryPtr->relativeToT, 20);
  1130.       }
  1131.       printf ("\n");
  1132.     }
  1133.   }
  1134. }
  1135.  
  1136.  
  1137.  
  1138. /* printSymbol (tableEntryPtr, fieldWidth)
  1139. **
  1140. ** printSymbolOnFile (filePtr, tableEntryPtr, fieldWidth)
  1141. **
  1142. ** These routines are passed a pointer to a TableEntry.  They print the
  1143. ** string, translating non-printable characters into escape sequences.
  1144. ** The String should never contain any non-printables besides
  1145. ** \n, \t, \0, \r, \\, \", and \'.  If any are encountered, we
  1146. ** will abort the linker.  We do not print a terminating newline.
  1147. ** If the string is shorter than "fieldWidth", we pad it out with blanks.
  1148. */
  1149.  
  1150. void printSymbol (TableEntry * tableEntryPtr, int fieldWidth) {
  1151.   printSymbolOnFile (stdout, tableEntryPtr, fieldWidth);
  1152. }
  1153.  
  1154. void printSymbolOnFile (FILE * fp, TableEntry * tableEntryPtr, int fieldWidth) {
  1155. #define BUF_SIZE 10
  1156.   int bufPtr, strPtr;
  1157.   char buffer[BUF_SIZE];
  1158.   int c;
  1159.   strPtr = 0;
  1160.   while (1) {
  1161.     /* If all characters printed, then exit. */
  1162.     if (strPtr >= tableEntryPtr->length) break;
  1163.     /* Fill up buffer */
  1164.     bufPtr = 0;
  1165.     while ((bufPtr < BUF_SIZE-2) && (strPtr < tableEntryPtr->length)) {
  1166.       c = tableEntryPtr->string [strPtr++];
  1167.       if (c == '\n') {
  1168.         buffer[bufPtr++] = '\\';
  1169.         buffer[bufPtr++] = 'n';
  1170.         fieldWidth -= 2;
  1171.       } else if (c == '\t') {
  1172.         buffer[bufPtr++] = '\\';
  1173.         buffer[bufPtr++] = 't';
  1174.         fieldWidth -= 2;
  1175.       } else if (c == '\0') {
  1176.         buffer[bufPtr++] = '\\';
  1177.         buffer[bufPtr++] = '0';
  1178.         fieldWidth -= 2;
  1179.       } else if (c == '\r') {
  1180.         buffer[bufPtr++] = '\\';
  1181.         buffer[bufPtr++] = 'r';
  1182.         fieldWidth -= 2;
  1183.       } else if (c == '\\') {
  1184.         buffer[bufPtr++] = '\\';
  1185.         buffer[bufPtr++] = '\\';
  1186.         fieldWidth -= 2;
  1187.       } else if (c == '\"') {
  1188.         buffer[bufPtr++] = '\\';
  1189.         buffer[bufPtr++] = '\"';
  1190.         fieldWidth -= 2;
  1191.       } else if (c == '\'') {
  1192.         buffer[bufPtr++] = '\\';
  1193.         buffer[bufPtr++] = '\'';
  1194.         fieldWidth -= 2;
  1195.       } else if ((c>=32) && (c<127)) {
  1196.         buffer[bufPtr++] = c;
  1197.         fieldWidth--;
  1198.       } else {
  1199.         fatalError ("Bad .o file; Symbol contains an unprintable char");
  1200.       }
  1201.     }
  1202.     /* Add \0 to buffer */
  1203.     buffer[bufPtr++] = '\0';
  1204.     /* Print buffer */
  1205.     fprintf (fp, "%s", buffer);
  1206.   }
  1207.   while (fieldWidth > 0) {
  1208.     fprintf (fp, " ");
  1209.     fieldWidth--;
  1210.   }
  1211. }
  1212.  
  1213.  
  1214.  
  1215. /* printTableArray ()
  1216. **
  1217. ** This routine runs through the table array and prints each entry.
  1218. */
  1219. void printTableArray () {
  1220.   int i;
  1221.   TableEntry * entryPtr;
  1222.   printf ("NUMB\tSYMBOL              \tVALUE   \tRELATIVE-TO\n");
  1223.   printf ("====\t====================\t========\t===========\n");
  1224.   for (i = 1; i<=maxSymbolNumber; i++) {
  1225.     entryPtr = tableArray [i];
  1226.     printf ("%d\t", i);
  1227.     printSymbol (entryPtr, 20);
  1228.     printf ("\t%08x", entryPtr->value);
  1229.     printf ("\t%d  ", entryPtr->relativeToS);
  1230.     if (entryPtr->relativeToT != NULL) {
  1231.       printSymbol (entryPtr->relativeToT, 20);
  1232.     }
  1233.     printf ("\n");
  1234.   }
  1235. }
  1236.  
  1237.  
  1238.  
  1239. /* lookup (givenEntry) -> TableEntry
  1240. **
  1241. ** This routine is passed a pointer to a TableEntry.  It looks that
  1242. ** entry up in the symbol table.  If there is already an entry with the
  1243. ** same string, then this routine returns a ptr to it.  Otherwise, this
  1244. ** routine adds this TableEntry to the symbol table and returns NULL to
  1245. ** indicate that is was added.
  1246. */
  1247. TableEntry * lookup (TableEntry * givenEntry) {
  1248.   unsigned hashVal = 0, g;
  1249.   char * p, * q;
  1250.   int i;
  1251.   TableEntry * entryPtr;
  1252.  
  1253.   /* Compute the hash value for the givenEntry and set hashVal to it. */
  1254.   for ( p = givenEntry->string, i=0;
  1255.         i < givenEntry->length;
  1256.         p++, i++ ) {
  1257.     hashVal = (hashVal << 4) + (*p);
  1258.     if (g = hashVal & 0xf0000000) {
  1259.       hashVal = hashVal ^ (g >> 24);
  1260.       hashVal = hashVal ^ g;
  1261.     }
  1262.   }
  1263.   hashVal %= SYMBOL_TABLE_HASH_SIZE;
  1264.  
  1265.   /* Search the linked list and return it if we find it. */
  1266.   for (entryPtr = symbolTableIndex [hashVal];
  1267.                       entryPtr;
  1268.                       entryPtr = entryPtr->next) {
  1269.     if (bytesEqual (entryPtr->string,
  1270.                     givenEntry->string,
  1271.                     entryPtr->length,
  1272.                     givenEntry->length)) {
  1273.       return entryPtr;
  1274.     }
  1275.   }
  1276.  
  1277.   /* Add the givenEntry to the appropriate linked list and return NULL. */
  1278.   givenEntry->next = symbolTableIndex [hashVal];
  1279.   symbolTableIndex [hashVal] = givenEntry;
  1280.   return NULL;
  1281. }
  1282.  
  1283.  
  1284.  
  1285. /* resolveSymbols ()
  1286. **
  1287. ** This routine runs through the symbol table and sets each to an
  1288. ** absolute value.
  1289. */
  1290. void resolveSymbols () {
  1291.   int changes = 1;
  1292.   int hashVal;
  1293.   TableEntry * entryPtr, * relTo;
  1294.   while (changes) {
  1295.     changes = 0;
  1296.     for (hashVal = 0; hashVal<SYMBOL_TABLE_HASH_SIZE; hashVal++) {
  1297.       for (entryPtr = symbolTableIndex [hashVal];
  1298.                        entryPtr;
  1299.                        entryPtr = entryPtr->next) {
  1300.         /***
  1301.         printf ("Looking at ");
  1302.         printSymbol (entryPtr, 1);
  1303.         printf ("...\n");
  1304.         ***/
  1305.         if (entryPtr->relativeToT == absoluteEntry) {
  1306.           /* This symbol already has an absolute value. */
  1307.         } else {
  1308.           relTo = entryPtr->relativeToT;
  1309.           if (relTo == 0) {
  1310.             /* This symbol was imported in some file, but not exported
  1311.                from any file. */
  1312.           } else if (relTo->relativeToT == absoluteEntry) {
  1313.             /* This symbol is relative to a symbol with an absolute value
  1314.                so go ahead an update it. */
  1315.             entryPtr->value += relTo->value;
  1316.             entryPtr->relativeToT = absoluteEntry;
  1317.             entryPtr->relativeToS = 4;
  1318.             changes = 1;
  1319.           } else {
  1320.             /* This symbol is relative to a symbol that does not yet have
  1321.                a value, so we can do nothing during this pass. */
  1322.           }
  1323.         }
  1324.       }
  1325.     }
  1326.   }
  1327.  
  1328.   /* Now make a final pass through to print errors. */
  1329.   for (hashVal = 0; hashVal<SYMBOL_TABLE_HASH_SIZE; hashVal++) {
  1330.     for (entryPtr = symbolTableIndex [hashVal];
  1331.                      entryPtr;
  1332.                      entryPtr = entryPtr->next) {
  1333.       fflush (stdout);
  1334.       if (entryPtr == absoluteEntry) {
  1335.       } else if (entryPtr->relativeToT == absoluteEntry) {
  1336.       } else {
  1337.         relTo = entryPtr->relativeToT;
  1338.         if (relTo == 0) {
  1339.           errorsDetected++;
  1340.           fprintf (stderr, "BLITZ Linker Error: The symbol \"");
  1341.           printSymbolOnFile (stderr, entryPtr, 1);
  1342.           fprintf (stderr, "\" is imported in file \"%s\", but is not exported from any file.\n", entryPtr->filename);
  1343.         } else if (relTo != absoluteEntry) {
  1344.           errorsDetected++;
  1345.           fprintf (stderr, "BLITZ Linker Error: Symbol \"");
  1346.           printSymbolOnFile (stderr, entryPtr, 1);
  1347.           fprintf (stderr, "\" depends on \"");
  1348.           printSymbolOnFile (stderr, relTo, 1);
  1349.           fprintf (stderr, "\", which had problems.\n");
  1350.  
  1351.         }
  1352.       }
  1353.     }
  1354.   }
  1355. }
  1356.  
  1357.  
  1358.  
  1359. /* performRelocations ()
  1360. **
  1361. ** Run thru all relocation records in all files and update
  1362. ** the segments by modifying the locations.  In other words, perform
  1363. ** each relocation action.
  1364. */
  1365. void performRelocations () {
  1366.   FileInfo * file;
  1367.   RelocInfo * rel;
  1368.   int addrOfInstruction;
  1369.   char * ptr;
  1370.   int newValue, relOffset;
  1371.  
  1372.   /* Each iteration of this loop looks at a .o file. */
  1373.   for (file=inputFileList; file!=NULL; file=file->next) {
  1374.     if (commandOptionL) {
  1375.       printf (" Processing file %s...\n", file->filename);
  1376.       printRelocationHeader ();
  1377.     }
  1378.  
  1379.     /* Each iteration of this loop looks at another relocation action. */
  1380.     for (rel=file->relocList; rel!=NULL; rel=rel->next) {
  1381.  
  1382.       /* Print the relocation record */
  1383.       printRelocationRecord (rel);
  1384.  
  1385.       newValue = (rel->relativeTo->value) + (rel->offset);
  1386.       if (rel->inText == 1) {
  1387.         ptr = (char *) (
  1388.                          rel->locationToUpdate
  1389.                           + file->textAddr
  1390.                           - textStartAddr
  1391.                           + (int) textSegment
  1392.                        );
  1393.       } else if (rel->inText == 2) {
  1394.         ptr = (char *) (
  1395.                          rel->locationToUpdate
  1396.                           + file->dataAddr
  1397.                           - dataStartAddr
  1398.                           + (int) dataSegment
  1399.                        );
  1400.       }
  1401.       if (rel->type == 1) {  /* 8-bits */
  1402.         if (get8 (ptr) != 0) {
  1403.           printErrorAndExit (file,
  1404.               "PROGRAM LOGIC ERROR - Previous relocation value not 0x00");
  1405.         }
  1406.         if ((newValue < -128) | (newValue > 255)) {
  1407.           warningsDetected++;
  1408.           fprintf (stderr,
  1409.             "BLITZ Linker Warning: 8-bit value %d (0x%08x) is out of range.\n",
  1410.             newValue, newValue);
  1411.           fprintf (stderr,
  1412.             "                      (File = %s, source line number = %d)\n",
  1413.             file->filename, rel->sourceLineNumber);
  1414.         }
  1415.         put8 (ptr, newValue);
  1416.       } else if (rel->type == 2) { /* 16-bits */
  1417.         if (get16 (ptr) != 0) {
  1418.           printErrorAndExit (file,
  1419.                "PROGRAM LOGIC ERROR - Previous relocation value not 0x0000");
  1420.         }
  1421.         if ((newValue < -32768) | (newValue > 32767)) {
  1422.           warningsDetected++;
  1423.           fprintf (stderr,
  1424.             "BLITZ Linker Warning: 16-bit value %d (0x%08x) is out of range.\n",
  1425.             newValue, newValue);
  1426.           fprintf (stderr,
  1427.             "                      (File = %s, source line number = %d)\n",
  1428.             file->filename, rel->sourceLineNumber);
  1429.         }
  1430.         put16 (ptr, newValue);
  1431.       } else if (rel->type == 3) { /* 24-bits */
  1432.         if (rel->inText == 1) {
  1433.           addrOfInstruction = rel->locationToUpdate + file->textAddr;
  1434.         } else if (rel->inText == 2) {
  1435.           addrOfInstruction = rel->locationToUpdate + file->dataAddr;
  1436.         } else {
  1437.           printErrorAndExit (file,
  1438.             "PROGRAM LOGIC ERROR - Bad switch value during relocation");
  1439.         }
  1440.         relOffset = newValue - addrOfInstruction;
  1441.         if ((addrOfInstruction & 0x00ffffff)
  1442.                    + relOffset !=
  1443.                    ((newValue  & 0x00ffffff))) {
  1444.           warningsDetected++;
  1445.           fprintf (stderr,
  1446.             "BLITZ Linker Warning: Relative offset (%08x) exceeds 24-bit limit.\n", relOffset);
  1447.           fprintf (stderr,
  1448.             "                      (File = %s, source line number = %d)\n",
  1449.             file->filename, rel->sourceLineNumber);
  1450.         }
  1451.         if (get24 (ptr) != 0) {
  1452.           printErrorAndExit (file,
  1453.             "PROGRAM LOGIC ERROR - Previous relocation value not 0x000000");
  1454.         }
  1455.         put24 (ptr, relOffset);
  1456.       } else if (rel->type == 4) { /* 32-bits */
  1457.         if (get32 (ptr) != 0) {
  1458.           printErrorAndExit (file,
  1459.             "PROGRAM LOGIC ERROR - Previous relocation value not 0x00000000");
  1460.         }
  1461.         put32 (ptr, newValue);
  1462.       } else if (rel->type == 5) { /* set-hi */
  1463.         if (get16 (ptr) != 0) {
  1464.           printErrorAndExit (file,
  1465.             "PROGRAM LOGIC ERROR - Previous relocation value not 0x0000");
  1466.         }
  1467.         put16 (ptr, (newValue >> 16) & 0x0000ffff);
  1468.       } else if (rel->type == 6) { /* set-lo */
  1469.         if (get16 (ptr) != 0) {
  1470.           printErrorAndExit (file,
  1471.             "PROGRAM LOGIC ERROR - Previous relocation value not 0x0000");
  1472.         }
  1473.         put16 (ptr, newValue & 0x0000ffff);
  1474.       } else if (rel->type == 7) { /* ldaddr */
  1475.         if (rel->inText == 1) {
  1476.           addrOfInstruction = rel->locationToUpdate + file->textAddr;
  1477.         } else if (rel->inText == 2) {
  1478.           addrOfInstruction = rel->locationToUpdate + file->dataAddr;
  1479.         } else {
  1480.           printErrorAndExit (file,
  1481.             "PROGRAM LOGIC ERROR - Bad switch value during relocation");
  1482.         }
  1483.         relOffset = newValue - addrOfInstruction;
  1484.         if ((addrOfInstruction & 0x0000ffff)
  1485.                    + relOffset !=
  1486.                    ((newValue  & 0x0000ffff))) {
  1487.           warningsDetected++;
  1488.           fprintf (stderr,
  1489.             "BLITZ Linker Warning: Relative offset (%08x) exceeds 16-bit limit.\n", relOffset);
  1490.           fprintf (stderr,
  1491.             "                      (File = %s, source line number = %d)\n",
  1492.             file->filename, rel->sourceLineNumber);
  1493.         }
  1494.         if (get16 (ptr+2) != 0) {
  1495.           printErrorAndExit (file,
  1496.             "PROGRAM LOGIC ERROR - Previous relocation value not 0x0000");
  1497.         }
  1498.         put16 (ptr+2, relOffset);
  1499.       } else {
  1500.         printErrorAndExit (file,
  1501.           "PROGRAM LOGIC ERROR - Invalid relocation type");
  1502.       }
  1503.     }
  1504.   }
  1505. }
  1506.  
  1507.  
  1508.  
  1509. /* get8 (ptr) --> int
  1510. ** get16 (ptr) --> int
  1511. ** get24 (ptr) --> int
  1512. ** get32 (ptr) --> int
  1513. **
  1514. ** These routines are passed a pointer.  They read a value from memory
  1515. ** and return it as an integer.  When getting an 8, 16, or 24 bit value
  1516. ** from memory, the high-order bits in the result are set to zero.   The
  1517. ** ptr need not be properly aligned.  In the case of 24-bits, the ptr points
  1518. ** to the word, i.e., the byte before the 24-bits.  In the other cases,
  1519. ** the ptr points to the data itself.
  1520. */
  1521.  
  1522. int get8 (char * ptr){
  1523.   int val = * ptr;
  1524.   return (val & 0x000000ff);
  1525. }
  1526.  
  1527. int get16 (char * ptr){
  1528.   union fourBytes {
  1529.     char chars [4];
  1530.     unsigned int i;
  1531.   } fourBytes;
  1532.   fourBytes.chars[2] = * (ptr+0);
  1533.   fourBytes.chars[3] = * (ptr+1);
  1534.   return (fourBytes.i & 0x0000ffff); 
  1535. }
  1536.  
  1537. int get24 (char * ptr){
  1538.   union fourBytes {
  1539.     char chars [4];
  1540.     unsigned int i;
  1541.   } fourBytes;
  1542.   fourBytes.chars[1] = * (ptr+1);
  1543.   fourBytes.chars[2] = * (ptr+2);
  1544.   fourBytes.chars[3] = * (ptr+3);
  1545.   return fourBytes.i & 0x00ffffff;
  1546. }
  1547.  
  1548. int get32 (char * ptr){
  1549.   union fourBytes {
  1550.     char chars [4];
  1551.     unsigned int i;
  1552.   } fourBytes;
  1553.   fourBytes.chars[0] = * (ptr+0);
  1554.   fourBytes.chars[1] = * (ptr+1);
  1555.   fourBytes.chars[2] = * (ptr+2);
  1556.   fourBytes.chars[3] = * (ptr+3);
  1557.   return fourBytes.i;
  1558. }
  1559.  
  1560.  
  1561.  
  1562. /* put8 (ptr, value)
  1563. ** put16 (ptr, value)
  1564. ** put24 (ptr, value)
  1565. ** put32 (ptr, value)
  1566. **
  1567. ** These routines are passed a pointer and a value.  They store that value
  1568. ** in memory.  When storing 8, 16, and 24 bits, the high-order bits of
  1569. ** the value are ignored.  The ptr need not be properly aligned.
  1570. ** In the case of 24-bits, the ptr points to the word, i.e., the byte before
  1571. ** the 24-bits.  In the other cases, the ptr points to the data itself.
  1572. */
  1573.  
  1574. void put8 (char * ptr, int value){
  1575.   int val = value & 0x000000ff;
  1576.   *ptr = val;
  1577. }
  1578.  
  1579. void put16 (char * ptr, int value){
  1580.   union fourBytes {
  1581.     char chars [4];
  1582.     unsigned int i;
  1583.   } fourBytes;
  1584.   fourBytes.i = value;
  1585.   * (ptr+0) = fourBytes.chars[2];
  1586.   * (ptr+1) = fourBytes.chars[3];
  1587. }
  1588.  
  1589. void put24 (char * ptr, int value){
  1590.   union fourBytes {
  1591.     char chars [4];
  1592.     unsigned int i;
  1593.   } fourBytes;
  1594.   fourBytes.i = value;
  1595.   * (ptr+1) = fourBytes.chars[1];
  1596.   * (ptr+2) = fourBytes.chars[2];
  1597.   * (ptr+3) = fourBytes.chars[3];
  1598. }
  1599.  
  1600. void put32 (char * ptr, int value){
  1601.   union fourBytes {
  1602.     char chars [4];
  1603.     unsigned int i;
  1604.   } fourBytes;
  1605.   fourBytes.i = value;
  1606.   * (ptr+0) = fourBytes.chars[0];
  1607.   * (ptr+1) = fourBytes.chars[1];
  1608.   * (ptr+2) = fourBytes.chars[2];
  1609.   * (ptr+3) = fourBytes.chars[3];
  1610. }
  1611.  
  1612.  
  1613.  
  1614. /* printRelocationHeader ()
  1615. **
  1616. ** Print the column headings.
  1617. */
  1618. void printRelocationHeader () {
  1619.   if (!commandOptionL) return;
  1620.   printf ("        Source  Type    Locatn-to-modify New-val  Relative-to\n");
  1621.   printf ("        ======= ======= ================ ======== ===========\n");
  1622. }
  1623.  
  1624.  
  1625.  
  1626. /* printRelocationRecord (rel)
  1627. **
  1628. ** Print a single RelocInfo record.
  1629. */
  1630. void printRelocationRecord (RelocInfo * rel) {
  1631.   if (!commandOptionL) return;
  1632.   printf ("\t");
  1633.   printf ("%5d   ", rel->sourceLineNumber);
  1634.   if (rel->type == 1) printf ("8-bit\t");
  1635.   if (rel->type == 2) printf ("16-bit\t");
  1636.   if (rel->type == 3) printf ("24-bit\t");
  1637.   if (rel->type == 4) printf ("32-bit\t");
  1638.   if (rel->type == 5) printf ("set-hi\t");
  1639.   if (rel->type == 6) printf ("set-lo\t");
  1640.   if (rel->type == 7) printf ("ldaddr\t");
  1641.   printf ("%08x ", rel->locationToUpdate);
  1642.   if (rel->inText == 1) {
  1643.     printf (".text\t");
  1644.   } else if (rel->inText == 2) {
  1645.     printf (".data\t");
  1646.   } else {
  1647.     printf ("*****\t");
  1648.   }
  1649.   printf (" %08x ", rel->offset);
  1650.   printSymbol (rel->relativeTo, 1);
  1651.   printf ("\n");
  1652. }
  1653.  
  1654.  
  1655.  
  1656. /* readRelocationRecords (file)
  1657. **
  1658. ** This routine reads in all the relocation records from a single .o
  1659. ** file.  It allocates a RelocInfo record for each, chains them togther
  1660. ** in a linked list, and makes file->relocList point to the new list.
  1661. */
  1662. void readRelocationRecords (FileInfo * file) {
  1663.   RelocInfo * rel;
  1664.   int i;
  1665.   if (commandOptionL) {
  1666.     printf (" Processing this file's relocation records...\n");
  1667.   }
  1668.   file->relocList = NULL;
  1669.   while (1) {
  1670.  
  1671.     /* Read in the "type" field (1, 2, 3, 4, 5, 6, or 7). */
  1672.     i = readInteger (file);
  1673.     if (i == 0) break;
  1674.     if ((i<1) | (i>7)) {
  1675.       printErrorAndExit (file, "Invalid reloc record");
  1676.     }
  1677.  
  1678.     /* Allocate a RelocInfo struct. */
  1679.     rel = (RelocInfo *) calloc (1, sizeof (RelocInfo));
  1680.     if (rel == NULL) {
  1681.       fatalError ("Calloc failed - insufficient memory available");
  1682.     }
  1683.     rel->type = i;
  1684.  
  1685.     /* Read in the "locationToUpdate" field. */
  1686.     rel->locationToUpdate = readInteger (file);
  1687.  
  1688.     /* Read in inText (1=text, 2=data). */
  1689.     rel->inText = readInteger (file);
  1690.     if ((rel->inText != 1) & (rel->inText != 2)) {
  1691.       printErrorAndExit (file, "Invalid reloc record");
  1692.     }
  1693.  
  1694.     /* Read in the "offset" field. */
  1695.     rel->offset = readInteger (file);
  1696.  
  1697.     /* Read in "relativeTo" and adjust from symbol number to TableEntry. */
  1698.     i = readInteger (file);
  1699.     if ((i<1) | (i>maxSymbolNumber)) {
  1700.       printErrorAndExit (file, "Invalid reloc record");
  1701.     }
  1702.     rel->relativeTo = tableArray [i];
  1703.  
  1704.     /* Read in the "sourceLineNumber" field. */
  1705.     rel->sourceLineNumber = readInteger (file);
  1706.  
  1707.     /* Link this record into the growing linked list. */
  1708.     rel->next = file->relocList;
  1709.     file->relocList = rel;
  1710.   }
  1711. }
  1712.  
  1713.  
  1714.  
  1715. /* addLabels ()
  1716. **
  1717. ** This routine runs through the .o files.  For each, it reads its
  1718. ** labels and adds them to the symbol table.  It "uniqifies" each label
  1719. ** first.  In other words, if there is already an entry for this label, 
  1720. ** we modify the label (from "aLabel" to "aLabel_43") until it is unique.
  1721. ** The value of each label is an address in the .text, .data, or .bss
  1722. ** segment in this file.
  1723. **
  1724. ** We are subverting the symbol table somewhat, here.  We are done processing
  1725. ** symbols by this time, so we can just add the labels to the symbol table
  1726. ** as if they were first-class symbols.  We will ignore all fields
  1727. ** in the symbol table entry except "value", "length" and "string".
  1728. ** Then, we'll go through the table and add all entries to the a.out file.
  1729. */
  1730. void addLabels () {
  1731.   FileInfo * file;
  1732.   LabelEntry * entryPtr;
  1733.   int foundIt, unique;
  1734.   int relativeTo, value, len, j, magic;
  1735.   char * q, * where;
  1736.  
  1737.   for (file=inputFileList; file!=NULL; file=file->next) {
  1738.     /***
  1739.     printf ("==========  Processing file %s  ==========\n", file->filename);
  1740.     ***/
  1741.     while (1) {
  1742.       relativeTo = readInteger (file);
  1743.       if (relativeTo == 0) break;
  1744.       value = readInteger (file);
  1745.       len = readInteger (file);
  1746.   
  1747.       /* Create a LabelEntry and initialize it.  Leave space for uniquifier. */
  1748.       entryPtr = (LabelEntry *) calloc (1, sizeof (LabelEntry) + len + 1 + 8);
  1749.       if (entryPtr == 0) {
  1750.         fatalError ("Calloc failed - insufficient memory available");
  1751.       }
  1752.       entryPtr->length = len;
  1753.       entryPtr->value = value;
  1754.       if (relativeTo == 1) {
  1755.         entryPtr->value = file->textAddr + value;
  1756.       } else if (relativeTo == 2) {
  1757.         entryPtr->value = file->dataAddr + value;
  1758.       } else if (relativeTo == 3) {
  1759.         entryPtr->value = file->bssAddr + value;
  1760.       } else {
  1761.         printErrorAndExit (file, "Invalid label record");
  1762.       }
  1763.   
  1764.       /* Read in the characters and move into this TableEntry. */
  1765.       for (q=entryPtr->string, j=len;
  1766.            j>0;
  1767.            q++, j--) {
  1768.         *q = readByte (file);
  1769.       }
  1770.       /*** printf ("  Processing %s... ", entryPtr->string); ***/
  1771.   
  1772.       /* Look this string up in the symbol table. */
  1773.       foundIt = lookupLabel (entryPtr);
  1774.       if (!foundIt) {    /* if not found... */
  1775.         /* ...then it will have gotten added to the symbol table. */
  1776.         /*** printf ("Not found.  It was added.\n"); ***/
  1777.       /* If found in the table... */
  1778.       } else {
  1779.         /*** printf ("Found.\n"); ***/
  1780.         /* Begin uniquifying the label. */
  1781.         unique = 1;
  1782.         /* Set "where" to point to the addr of the \000 char */
  1783.         for (where=entryPtr->string; *where; where++) ;
  1784.         while (1) {
  1785.           sprintf (where, "_%d", unique++);
  1786.           entryPtr->length = strlen (entryPtr->string);
  1787.           /*** printf ("    Searching for %s...\n", entryPtr->string); ***/
  1788.           if (!lookupLabel (entryPtr)) break;
  1789.         }
  1790.       }
  1791.     }
  1792.     magic = readInteger (file);
  1793.     if (magic != 0x2a2a2a2a) {
  1794.       printErrorAndExit (file, "Invalid **** separator");
  1795.     }
  1796.   }
  1797. }
  1798.  
  1799.  
  1800.  
  1801. /* lookupLabel (newEntry) -> Boolean
  1802. **
  1803. ** This routine is passed a pointer to a LabelEntry.  It looks that
  1804. ** entry up in the label table.  If there is already an entry with the
  1805. ** same string, then this routine returns TRUE.  Otherwise, this
  1806. ** routine adds this LabelEntry to the label table and returns FALSE to
  1807. ** indicate that is was added.
  1808. */
  1809. int lookupLabel (LabelEntry * newEntry) {
  1810.   unsigned hashVal = 0, g;
  1811.   char * p, * q;
  1812.   int i;
  1813.   LabelEntry * entryPtr;
  1814.  
  1815.   /* Compute the hash value for the newEntry and set hashVal to it. */
  1816.   for ( p = newEntry->string, i=0;
  1817.         i < newEntry->length;
  1818.         p++, i++ ) {
  1819.     hashVal = (hashVal << 4) + (*p);
  1820.     if (g = hashVal & 0xf0000000) {
  1821.       hashVal = hashVal ^ (g >> 24);
  1822.       hashVal = hashVal ^ g;
  1823.     }
  1824.   }
  1825.   hashVal %= LABEL_TABLE_HASH_SIZE;
  1826.  
  1827.   /* Search the linked list and return TRUE if we find it. */
  1828.   for (entryPtr = labelTableIndex [hashVal];
  1829.                       entryPtr;
  1830.                       entryPtr = entryPtr->next) {
  1831.     if (strcmp (entryPtr->string, newEntry->string) == 0) {
  1832.       return 1;
  1833.     }
  1834.   }
  1835.  
  1836.   /* Add the newEntry to the appropriate linked list and return FALSE. */
  1837.   newEntry->next = labelTableIndex [hashVal];
  1838.   labelTableIndex [hashVal] = newEntry;
  1839.   return 0;
  1840. }
  1841.  
  1842.  
  1843.  
  1844. /* writeLabels ()
  1845. **
  1846. ** This routine runs through the label table and writes an entry to
  1847. ** the a.out file.  It also prints the label table, if that is required.
  1848. */
  1849. void writeLabels () {
  1850.   int hashVal;
  1851.   char * p;
  1852.   int i, len;
  1853.   LabelEntry * entryPtr;
  1854.   if (commandOptionS) {
  1855.     printf ("ADDRESS  LABEL\n");
  1856.     printf ("======== =============\n");
  1857.   }
  1858.   for (hashVal = 0; hashVal<LABEL_TABLE_HASH_SIZE; hashVal++) {
  1859.     for (entryPtr = labelTableIndex [hashVal];
  1860.                        entryPtr;
  1861.                        entryPtr = entryPtr->next) {
  1862.       len = strlen (entryPtr->string);
  1863.       writeInteger (len);
  1864.       writeInteger (entryPtr->value);
  1865.       i = fwrite (entryPtr->string, 1, len, outputFile);
  1866.       if (i != len) {
  1867.         fatalError ("Error while writing data to output executable file");
  1868.       }
  1869.       if (commandOptionS) {
  1870.         printf ("%08x ", entryPtr->value);
  1871.         printf ("%s\n", entryPtr->string);
  1872.       }
  1873.     }
  1874.   }
  1875.   writeInteger (0);
  1876.   if (commandOptionS) {
  1877.     printf ("\n");
  1878.   }
  1879. }
  1880.