Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1775,22 +1775,6 @@ return H; } -// Returns a number of hash buckets to accomodate given number of elements. -// We want to choose a moderate number that is not too small (which -// causes too many hash collisions) and not too large (which wastes -// disk space.) -// -// We return a prime number because it (is believed to) achieve good -// hash distribution. -static size_t getBucketSize(size_t NumSymbols) { - // List of largest prime numbers that are not greater than 2^n + 1. - for (size_t N : {131071, 65521, 32749, 16381, 8191, 4093, 2039, 1021, 509, - 251, 127, 61, 31, 13, 7, 3, 1}) - if (N <= NumSymbols) - return N; - return 0; -} - // Add symbols to this symbol hash table. Note that this function // destructively sort a given vector -- which is needed because // GNU-style hash table places some sorting requirements. @@ -1813,7 +1797,12 @@ Symbols.push_back({B, Ent.StrTabOffset, hashGnu(B->getName())}); } - NBuckets = getBucketSize(Symbols.size()); + // We chose load factor 4 for the on-disk hash table. For each hash + // collision, the dynamic linker will compare a uint32_t hash value. + // Since the integer comparison is quite fast, we believe we can make + // the load factor even larger. 4 is just a conservative choice. + NBuckets = std::max(Symbols.size() / 4, 1); + std::stable_sort(Symbols.begin(), Symbols.end(), [&](const Entry &L, const Entry &R) { return L.Hash % NBuckets < R.Hash % NBuckets; Index: test/ELF/gc-sections-shared.s =================================================================== --- test/ELF/gc-sections-shared.s +++ test/ELF/gc-sections-shared.s @@ -34,28 +34,28 @@ # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: foo +# CHECK-NEXT: Name: baz # CHECK-NEXT: Value: # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: # CHECK-NEXT: Other: -# CHECK-NEXT: Section: .text +# CHECK-NEXT: Section: Undefined # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: qux +# CHECK-NEXT: Name: foo # CHECK-NEXT: Value: # CHECK-NEXT: Size: -# CHECK-NEXT: Binding: Weak +# CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: # CHECK-NEXT: Other: -# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: baz +# CHECK-NEXT: Name: qux # CHECK-NEXT: Value: # CHECK-NEXT: Size: -# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Binding: Weak # CHECK-NEXT: Type: # CHECK-NEXT: Other: # CHECK-NEXT: Section: Undefined @@ -90,31 +90,31 @@ # CHECK2-NEXT: Section: .text # CHECK2-NEXT: } # CHECK2-NEXT: Symbol { -# CHECK2-NEXT: Name: qux +# CHECK2-NEXT: Name: baz # CHECK2-NEXT: Value: # CHECK2-NEXT: Size: -# CHECK2-NEXT: Binding: Weak +# CHECK2-NEXT: Binding: Global # CHECK2-NEXT: Type: # CHECK2-NEXT: Other: # CHECK2-NEXT: Section: Undefined # CHECK2-NEXT: } # CHECK2-NEXT: Symbol { -# CHECK2-NEXT: Name: foo +# CHECK2-NEXT: Name: qux # CHECK2-NEXT: Value: # CHECK2-NEXT: Size: -# CHECK2-NEXT: Binding: Global +# CHECK2-NEXT: Binding: Weak # CHECK2-NEXT: Type: # CHECK2-NEXT: Other: -# CHECK2-NEXT: Section: .text +# CHECK2-NEXT: Section: Undefined # CHECK2-NEXT: } # CHECK2-NEXT: Symbol { -# CHECK2-NEXT: Name: baz +# CHECK2-NEXT: Name: foo # CHECK2-NEXT: Value: # CHECK2-NEXT: Size: # CHECK2-NEXT: Binding: Global # CHECK2-NEXT: Type: # CHECK2-NEXT: Other: -# CHECK2-NEXT: Section: Undefined +# CHECK2-NEXT: Section: .text # CHECK2-NEXT: } # CHECK2-NEXT: ]