Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /****************************  omfhash.cpp  **********************************
  2. * Author:        Agner Fog
  3. * Date created:  2007-02-14
  4. * Last modified: 2007-02-14
  5. * Project:       objconv
  6. * Module:        omfhash.cpp
  7. * Description:
  8. * This module contains code for searching and making hash tables for OMF
  9. * libraries.
  10. *
  11. * Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses
  12. *****************************************************************************/
  13.  
  14. #include "stdafx.h"
  15.  
  16. void COMFHashTable::Init(SOMFHashBlock * blocks, uint32 NumBlocks) {
  17.    // Initialize
  18.    this->blocks = blocks;                        // Pointer to blocks
  19.    this->NumBlocks = NumBlocks;                  // Number of blocks
  20.    String = 0;
  21.    StringLength = 0;
  22. }
  23.  
  24. // Rotate right 16-bit word
  25. uint16 RotR(uint16 x, uint16 bits) {
  26.    return (x >> bits) | (x << (16 - bits));
  27. }
  28.  
  29. // Rotate left 16-bit word
  30. uint16 RotL(uint16 x, uint16 bits) {
  31.    return (x << bits) | (x >> (16 - bits));
  32. }
  33.  
  34. void COMFHashTable::MakeHash(int8 * name) {
  35.    // Compute hash according to the official algorithm
  36.    uint8 * pb;                                   // Pointer for forward scan through string
  37.    uint8 * pe;                                   // Pointer for backwards scan through string
  38.    uint16 c;                                     // Current character converted to lower case
  39.    uint16 BlockX;                                // Calculate block hash
  40.    uint16 BucketX;                               // Calculate block hash
  41.    String = (uint8*)name;                        // Type cast string to unsigned char *
  42.    StringLength = (uint32)strlen(name);
  43.    if (StringLength > 255 || StringLength == 0) {
  44.       // String too long
  45.       err.submit(1204, name);                    // Warning: truncating
  46.       StringLength = 255;
  47.       String[StringLength] = 0;                  // Truncation modifies string source!
  48.    }
  49.    String = (uint8*)name;                        // Type cast to unsigned characters
  50.    pb = String;                                  // Initialize pointer for forward scan
  51.    pe = String + StringLength;                   // Initialize pointer for backward scan
  52.    BlockX = BucketD = StringLength | 0x20;       // Initialize left-to-right scan
  53.    BucketX = BlockD = 0;                         // Initialize right-to-left scan
  54.  
  55.    // Scan loop
  56.    while (1) {
  57.       c = *(--pe) | 0x20;                        // Read character for backward scan, make lower case
  58.       BucketX = RotR(BucketX, 2) ^ c;            // Rotate, XOR
  59.       BlockD  = RotL(BlockD,  2) ^ c;            // Rotate, XOR
  60.       if (pe == String) break;                   // Stop loop when backward scan finished
  61.       c = *(pb++) | 0x20;                        // Read character for forward scan, make lower case
  62.       BlockX  = RotL(BlockX,  2) ^ c;            // Rotate, XOR
  63.       BucketD = RotR(BucketD, 2) ^ c;            // Rotate, XOR
  64.    }
  65.    // Make values modulo number of blocks / buckets
  66.    BlockX = BlockX % NumBlocks;
  67.    BlockD = BlockD % NumBlocks;
  68.    if (BlockD == 0) BlockD = 1;
  69.    BucketX = BucketX % OMFNumBuckets;
  70.    BucketD = BucketD % OMFNumBuckets;
  71.    if (BucketD == 0) BucketD = 1;
  72.    StartBlock  = BlockX;
  73.    StartBucket = BucketX;
  74. }
  75.  
  76.  
  77. int  COMFHashTable::FindString(uint32 & ModulePage, uint32 & Conflicts) {
  78.    // Search for String.
  79.    // Returns number of occurrences of String
  80.    // Module receives the module page for the first occurrence
  81.    // Conflicts receives the number of conflicting entries encountered before the match
  82.    uint32 Num = 0;                               // Number of occurrences of string found
  83.    uint16 Block;                                 // Block number
  84.    uint16 Bucket;                                // Bucket number
  85.    uint32 StringIndex;                           // Index to string
  86.    Conflicts = 0;                                // Start counting Conflicts
  87.  
  88.    Block = StartBlock;
  89.    Bucket = StartBucket;
  90.  
  91.    // Loop through blocks
  92.    do {
  93.  
  94.       // Loop through buckets
  95.       do {
  96.  
  97.          // String index of current bucket
  98.          StringIndex = blocks[Block].b.Buckets[Bucket];
  99.          if (StringIndex == 0) {
  100.             if (blocks[Block].b.FreeSpace < 0xff) {
  101.                // Empty bucket found. End of search
  102.                return Num;
  103.             }
  104.             else {
  105.                // Block is full. Search next block
  106.  
  107.                // Note: It would be logical to set StartBucket = Bucket
  108.                // here in order to allow all buckets in the next block
  109.                // to be tried, but the official algorithm doesn't seem
  110.                // to do so!?
  111.                // StartBucket = Bucket;
  112.  
  113.                break;
  114.             }
  115.          }
  116.          // Bucket contains a string. Is it the same string?
  117.          if (blocks[Block].Strings[StringIndex*2] == StringLength
  118.          && strncmp((int8*)&blocks[Block].Strings[StringIndex*2+1], (int8*)String, StringLength) == 0) {
  119.             // Matching string found
  120.             Num++;
  121.             if (Num == 1) {
  122.                // First occurrence. Save module number
  123.                ModulePage = *(uint16*)&blocks[Block].Strings[StringIndex*2+1+StringLength];
  124.             }
  125.          }
  126.          else {
  127.             // Conflicting string found
  128.             Conflicts++;
  129.          }
  130.          // Next bucket
  131.          Bucket = (Bucket + BucketD) % OMFNumBuckets;
  132.       } while (Bucket != StartBucket);
  133.  
  134.       // Next block
  135.       Block = (Block + BlockD) % NumBlocks;
  136.    }  while (Block != StartBlock);
  137.    // Finished searching all blocks and buckets
  138.    return Num;
  139. }
  140.  
  141. int COMFHashTable::InsertString(uint16 & ModulePage) {
  142.    // Insert string in hash table.
  143.    // Parameter:
  144.    // ModulePage = module address / page size
  145.    // Return value:
  146.    // 0 if success,
  147.    // 1 if identical string allready exists in the table. New string will not be entered.
  148.    //   ModulePage will receive the module page of the existing string in this case.
  149.    // 2 if table is full,
  150.    uint16 Block;                                 // Block number
  151.    uint16 Bucket;                                // Bucket number
  152.    uint32 StringIndex;                           // Index to string space
  153.    uint32 StringOffset;                          // Offset to string from begin of block
  154.    uint32 SpaceRequired;                         // Space required to store string
  155.  
  156.    SpaceRequired = StringLength + 3;             // Space for string + stringlength + module index
  157.    SpaceRequired = (SpaceRequired + 1) & uint32(-2);// Round up to nearest even
  158.  
  159.    Block = StartBlock;
  160.    Bucket = StartBucket;
  161.  
  162.    // Loop through blocks
  163.    do {
  164.  
  165.       // Loop through buckets
  166.       do {
  167.  
  168.          // String index of current bucket
  169.          StringIndex = blocks[Block].b.Buckets[Bucket];
  170.          if (StringIndex == 0) {
  171.             // Found empty bucket. Check if block has enough free space
  172.             if (uint32(OMFBlockSize) - blocks[Block].b.FreeSpace * 2 < SpaceRequired) {
  173.                // Not enough space in block.
  174.                // Continue with same bucket in next block.
  175.  
  176.                // Note: It would be logical to set StartBucket = Bucket
  177.                // here in order to allow all buckets in the next block
  178.                // to be tried, but the official algorithm doesn't seem
  179.                // to do so!?
  180.                // StartBucket = Bucket;
  181.                break;
  182.             }
  183.             // Enough space found. Enter string in bucket
  184.             StringIndex = blocks[Block].b.FreeSpace;
  185.             blocks[Block].b.Buckets[Bucket] = StringIndex;
  186.             // Address to store string
  187.             StringOffset = StringIndex * 2;
  188.             // Store string length
  189.             blocks[Block].Strings[StringOffset] = (uint8)StringLength;
  190.             // Copy string
  191.             memcpy(blocks[Block].Strings + StringOffset + 1, String, StringLength);
  192.             // Insert module page number
  193.             *(uint16*)(blocks[Block].Strings + StringOffset + 1 + StringLength) = ModulePage;
  194.             // Update free space
  195.             blocks[Block].b.FreeSpace += (uint8)(SpaceRequired / 2);
  196.             // Check if overflow
  197.             if (blocks[Block].b.FreeSpace == 0) blocks[Block].b.FreeSpace = 0xFF;
  198.             // Indicate success
  199.             return 0;
  200.          }
  201.          else {
  202.             // Bucket contains a string. Check if it is the same string
  203.             if (blocks[Block].Strings[StringIndex*2] == StringLength
  204.             && strncmp((int8*)(blocks[Block].Strings+StringIndex*2+1), (int8*)String, StringLength) == 0) {
  205.                // Identical string found. Return module index for existing string entry
  206.                ModulePage = *(uint16*)(blocks[Block].Strings+StringIndex*2+1+StringLength);
  207.                // Indicate failure
  208.                return 1;
  209.             }
  210.          }
  211.          // Bucket was full. Go to next bucket
  212.          Bucket = (Bucket + BucketD) % OMFNumBuckets;
  213.       } while (Bucket != StartBucket);
  214.  
  215.       // If we got here, we have found no empty bucket in the block or
  216.       // there was not enough string space in the block.
  217.       // We need to mark the block as full to tell the linker to
  218.       // continue in next block when searching for this string
  219.       // Whether the block has any empty buckets or not
  220.       blocks[Block].b.FreeSpace = 0xFF;
  221.  
  222.       // Go to next block
  223.       Block = (Block + BlockD) % NumBlocks;
  224.    }  while (Block != StartBlock);
  225.  
  226.    // Finished searching all blocks and buckets
  227.    // No empty space found. Indicate failure:
  228.    return 2;
  229. }
  230.  
  231.  
  232. // Table of prime numbers
  233. // You may add more prime numbers if very big library files are needed
  234. static const uint32 PrimeNumbers[] = {
  235.    1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
  236.    73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157,
  237.    163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241,
  238.    251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347,
  239.    349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439,
  240.    443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547,
  241.    557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643,
  242.    647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751,
  243.    757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859,
  244.    863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977,
  245.    983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063,
  246.    1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163,
  247.    1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259,
  248.    1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361,
  249.    1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453,
  250.    1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549,
  251.    1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621,
  252.    1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
  253.    1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847,
  254.    1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949,
  255.    1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039,
  256.    2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137,
  257.    2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251,
  258.    2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347,
  259.    2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437,
  260.    2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551,
  261.    2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671,
  262.    2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741,
  263.    2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843,
  264.    2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957,
  265.    2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067,
  266.    3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191,
  267.    3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307,
  268.    3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391,
  269.    3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517,
  270.    3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607,
  271.    3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701,
  272.    3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821,
  273.    3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919,
  274.    3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021,
  275.    4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133,
  276.    4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243,
  277.    4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357,
  278.    4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481,
  279.    4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591,
  280.    4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691,
  281.    4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801,
  282.    4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937,
  283.    4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021
  284. };
  285.  
  286. // Length of table
  287. static const uint32 PrimeNumbersLen = sizeof(PrimeNumbers)/sizeof(PrimeNumbers[0]);
  288.  
  289.  
  290. void COMFHashTable::MakeHashTable(CSList<SStringEntry> & StringEntries,
  291. CMemoryBuffer & StringBuffer, CMemoryBuffer & OutFile, CLibrary * Library) {
  292.    // Make hash table. Parameters:
  293.    // StringEntries[].String = name of each public symbol as offset into StringBuffer
  294.    // StringEntries[].Member = page address of member = offset / page size
  295.    // StringBuffer = contains all strings
  296.    // OutFile will receive the output hash table
  297.  
  298.    CSList<SOMFHashBlock> HashTable;              // Hash table
  299.    COMFHashTable TableHandler;                   // Hash table handler
  300.    uint32 NumBlocksI;                            // Number of blocks as index into prime number table
  301.    uint32 BlockI;                                // Block index
  302.    uint32 SymI;                                  // Symbol index
  303.    int8 * String;                                // Symbol name
  304.    uint16 Module1, Module2;                      // Module page = offset / page size
  305.    int    Result;                                // 0 = success
  306.  
  307.    // Estimate required number of blocks
  308.    NumBlocks = (StringEntries.GetNumEntries() * 8 + StringBuffer.GetDataSize()) / 256;
  309.    // Find nearest prime number >= NumBlocks, but stay within the range from 2 to 251.
  310.    // The minimum NumBlocks is 1, but some systems use 2 as the minimum.
  311.    // The maximum is 251, but some linkers may allow a higher number
  312.  
  313.    for (NumBlocksI = 1; NumBlocksI < 55; NumBlocksI++) {
  314.       if (PrimeNumbers[NumBlocksI] >= NumBlocks) break;
  315.    }
  316.  
  317.    // Try if this number of blocks is sufficient
  318.    while (NumBlocksI < PrimeNumbersLen) {
  319.  
  320.       // Get number of blocks from prime numbers table
  321.       NumBlocks = PrimeNumbers[NumBlocksI];
  322.  
  323.       // Check if <= 251
  324.       if (NumBlocks > 255) err.submit(1215); // Number of blocks exceeds official limit. May still work with some linkers
  325.  
  326.       // Allocate space for hash table
  327.       HashTable.SetNum(NumBlocks);
  328.       memset(&HashTable[0], 0, NumBlocks * OMFBlockSize);
  329.  
  330.       // Initialize hash table handler
  331.       TableHandler.Init(&HashTable[0], NumBlocks);
  332.  
  333.       // Set free space pointers
  334.       for (BlockI = 0; BlockI < NumBlocks; BlockI++) {
  335.          TableHandler.blocks[BlockI].b.FreeSpace = 19;
  336.       }
  337.       Result = 0;
  338.  
  339.       // Insert symbols
  340.       // Loop through symbols
  341.       for (SymI = 0; SymI < StringEntries.GetNumEntries(); SymI++) {
  342.  
  343.          // Symbol name
  344.          String = StringBuffer.Buf() + StringEntries[SymI].String;
  345.  
  346.          // Module page
  347.          Module1 = Module2 = StringEntries[SymI].Member;
  348.  
  349.          // Insert name in table
  350.          TableHandler.MakeHash(String);
  351.          Result = TableHandler.InsertString(Module2);
  352.  
  353.          if (Result == 1) {
  354.             // String already exists
  355.             // Compose error string "Modulename1 and Modulename2"
  356.             char ErrorModuleNames[64];
  357.             strcpy(ErrorModuleNames, Library->GetModuleName(Module1));
  358.             strcpy(ErrorModuleNames + strlen(ErrorModuleNames), " and ");
  359.             strcpy(ErrorModuleNames + strlen(ErrorModuleNames), Library->GetModuleName(Module2));
  360.             // submit error message
  361.             err.submit(1214, String, ErrorModuleNames);
  362.          }
  363.          if (Result == 2) {
  364.             // Table is full. Stop and repeat with a higher NumBlocks
  365.             break;
  366.          }
  367.       } // End of loop through symbols
  368.  
  369.       if (Result < 2) {
  370.          // Finished with success
  371.          // Store hash table
  372.          OutFile.Push(&HashTable[0], HashTable.GetNumEntries() * OMFBlockSize);
  373.          return;
  374.       }
  375.  
  376.       // Table is full. Try again with a higher number of blocks
  377.       NumBlocksI++;
  378.    }
  379.  
  380.    // End of loop through PrimeNumbers table
  381.    err.submit(2605);                             // Failed to make table
  382. }
  383.