diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 8d775d9ba6ec..891d33793556 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1775,22 +1775,6 @@ static uint32_t hashGnu(StringRef Name) { 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 @@ void GnuHashTableSection::addSymbols(std::vector &V) { 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; diff --git a/lld/test/ELF/gc-sections-shared.s b/lld/test/ELF/gc-sections-shared.s index 13be58cbbac9..2976213e910a 100644 --- a/lld/test/ELF/gc-sections-shared.s +++ b/lld/test/ELF/gc-sections-shared.s @@ -34,6 +34,15 @@ # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: baz +# CHECK-NEXT: Value: +# CHECK-NEXT: Size: +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: +# CHECK-NEXT: Other: +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { # CHECK-NEXT: Name: foo # CHECK-NEXT: Value: # CHECK-NEXT: Size: @@ -51,15 +60,6 @@ # CHECK-NEXT: Other: # CHECK-NEXT: Section: Undefined # CHECK-NEXT: } -# CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: baz -# CHECK-NEXT: Value: -# CHECK-NEXT: Size: -# CHECK-NEXT: Binding: Global -# CHECK-NEXT: Type: -# CHECK-NEXT: Other: -# CHECK-NEXT: Section: Undefined -# CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NOT: NEEDED @@ -90,6 +90,15 @@ # CHECK2-NEXT: Section: .text # CHECK2-NEXT: } # CHECK2-NEXT: Symbol { +# CHECK2-NEXT: Name: baz +# CHECK2-NEXT: Value: +# CHECK2-NEXT: Size: +# CHECK2-NEXT: Binding: Global +# CHECK2-NEXT: Type: +# CHECK2-NEXT: Other: +# CHECK2-NEXT: Section: Undefined +# CHECK2-NEXT: } +# CHECK2-NEXT: Symbol { # CHECK2-NEXT: Name: qux # CHECK2-NEXT: Value: # CHECK2-NEXT: Size: @@ -107,15 +116,6 @@ # CHECK2-NEXT: Other: # CHECK2-NEXT: Section: .text # CHECK2-NEXT: } -# CHECK2-NEXT: Symbol { -# CHECK2-NEXT: Name: baz -# CHECK2-NEXT: Value: -# CHECK2-NEXT: Size: -# CHECK2-NEXT: Binding: Global -# CHECK2-NEXT: Type: -# CHECK2-NEXT: Other: -# CHECK2-NEXT: Section: Undefined -# CHECK2-NEXT: } # CHECK2-NEXT: ] # CHECK2-NOT: NEEDED