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 / Beta / lddd.c < prev    next >
C/C++ Source or Header  |  2007-09-04  |  64KB  |  2,041 lines

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