1
1
mirror of https://github.com/rui314/mold.git synced 2024-12-29 11:24:36 +03:00
This commit is contained in:
Rui Ueyama 2021-03-15 11:58:42 +09:00
parent bfa6204b2a
commit 2e645809e8

View File

@ -651,47 +651,59 @@ void DynsymSection::add_symbol(Symbol *sym) {
void DynsymSection::sort_symbols() { void DynsymSection::sort_symbols() {
Timer t("sort_dynsyms"); Timer t("sort_dynsyms");
tbb::parallel_for((i64)1, (i64)symbols.size(), [&](i64 i) { struct T {
symbols[i]->dynsym_idx = i; Symbol *sym;
}); i32 idx;
u32 hash;
bool is_local() const {
return sym->esym->st_bind == STB_LOCAL;
}
};
std::vector<T> vec(symbols.size());
for (i32 i = 1; i < symbols.size(); i++)
vec[i] = {symbols[i], i, 0};
// In any ELF file, local symbols should precede global symbols. // In any ELF file, local symbols should precede global symbols.
tbb::parallel_sort(symbols.begin() + 1, symbols.end(), tbb::parallel_sort(vec.begin() + 1, vec.end(), [](const T &a, const T &b) {
[](Symbol *a, Symbol *b) { if (a.is_local() == b.is_local())
bool x = (a->esym->st_bind == STB_LOCAL); return a.idx < b.idx;
bool y = (b->esym->st_bind == STB_LOCAL); return a.is_local();
if (x == y)
return a->dynsym_idx < b->dynsym_idx;
return x;
}); });
auto first_global = std::partition_point( auto first_global = std::partition_point(vec.begin() + 1, vec.end(),
symbols.begin() + 1, symbols.end(), [](const T &x) {
[](Symbol *sym) { return sym->esym->st_bind == STB_LOCAL; }); return x.is_local();
});
// In any ELF file, the index of the first global symbols can be // In any ELF file, the index of the first global symbols can be
// found in the symtab's sh_info field. // found in the symtab's sh_info field.
shdr.sh_info = first_global - symbols.begin(); shdr.sh_info = first_global - vec.begin();
// If we have .gnu.hash section, it imposes more constraints // If we have .gnu.hash section, it imposes more constraints
// on the order of symbols. // on the order of symbols.
if (out::gnu_hash) { if (out::gnu_hash) {
i64 num_globals = symbols.end() - first_global; i64 num_globals = vec.end() - first_global;
out::gnu_hash->num_buckets = num_globals / out::gnu_hash->LOAD_FACTOR + 1; out::gnu_hash->num_buckets = num_globals / out::gnu_hash->LOAD_FACTOR + 1;
out::gnu_hash->symoffset = first_global - symbols.begin(); out::gnu_hash->symoffset = first_global - vec.begin();
tbb::parallel_sort(first_global, symbols.end(), [&](Symbol *a, Symbol *b) { tbb::parallel_for_each(first_global, vec.end(), [](T &x) {
i64 x = gnu_hash(a->name) % out::gnu_hash->num_buckets; x.hash = gnu_hash(x.sym->name) % out::gnu_hash->num_buckets;
i64 y = gnu_hash(b->name) % out::gnu_hash->num_buckets; });
if (x == y)
return a->dynsym_idx < b->dynsym_idx; tbb::parallel_sort(first_global, vec.end(), [&](const T &a, const T &b) {
return x < y; if (a.hash == b.hash)
return a.idx < b.idx;
return a.hash < b.hash;
}); });
} }
for (i64 i = 1; i < symbols.size(); i++) { for (i64 i = 1; i < symbols.size(); i++) {
name_indices.push_back(out::dynstr->add_string(symbols[i]->name)); symbols[i] = vec[i].sym;
symbols[i]->dynsym_idx = i; symbols[i]->dynsym_idx = i;
name_indices.push_back(out::dynstr->add_string(symbols[i]->name));
} }
} }