From c4d5a76223f74930add9014f2a77339eb80b737c Mon Sep 17 00:00:00 2001 From: Cary Coutant Date: Thu, 22 Dec 2016 14:06:24 -0800 Subject: Fix placement of forced local symbols in the dynamic symbol table. Gold was not placing forced-local symbols (e.g., hidden visibility) at the front of the dynamic symbol table, or including them in the count of local symbols recorded in the .dynsym section's sh_info field. gold/ * layout.cc (Layout::finalize): Track count of forced-local symbols in .dynsym. (Layout::create_symtab_sections): Add local_dynamic_count parameter; use that instead of sh_info value. (Layout::create_dynamic_symtab): Add pforced_local_dynamic_count parameter; pass it to Symtab::set_dynsym_indexes(). Include forced locals in sh_info value. Pass index of first real global to Dynobj::create_gnu_hash_table() and Dynobj::create_elf_hash_table(). * layout.h (Layout::create_symtab_sections): Add local_dynamic_count parameter. (Layout::create_dynamic_symtab): Add pforced_local_dynamic_count parameter. * symtab.cc (Symbol_table::set_dynsym_indexes): Add pforced_local_count parameter. Process forced-local symbols first and return the count. (Symbol_table::finalize): Update comments. * symtab.h (Symbol_table::set_dynsym_indexes): Add pforced_local_count parameter. (Symbol_table::first_dynamic_global_index_): Update comment. (Symbol_table::dynamic_count_): Update comment. * testsuite/Makefile.am (ifuncmod1.sh): New test case. * testsuite/Makefile.in: Regenerate. * testsuite/ifuncmod1.sh: New shell script. --- gold/symtab.cc | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) (limited to 'gold/symtab.cc') diff --git a/gold/symtab.cc b/gold/symtab.cc index d97fbdd..32c97fb 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -2473,18 +2473,42 @@ Symbol_table::add_undefined_symbol_from_command_line(const char* name) } // Set the dynamic symbol indexes. INDEX is the index of the first -// global dynamic symbol. Pointers to the symbols are stored into the -// vector SYMS. The names are added to DYNPOOL. This returns an -// updated dynamic symbol index. +// global dynamic symbol. Pointers to the global symbols are stored +// into the vector SYMS. The names are added to DYNPOOL. +// This returns an updated dynamic symbol index. unsigned int Symbol_table::set_dynsym_indexes(unsigned int index, + unsigned int* pforced_local_count, std::vector* syms, Stringpool* dynpool, Versions* versions) { std::vector as_needed_sym; + // First process all the symbols which have been forced to be local, + // as they must appear before all global symbols. + unsigned int forced_local_count = 0; + for (Forced_locals::iterator p = this->forced_locals_.begin(); + p != this->forced_locals_.end(); + ++p) + { + Symbol* sym = *p; + gold_assert(sym->is_forced_local()); + if (sym->has_dynsym_index()) + continue; + if (!sym->should_add_dynsym_entry(this)) + sym->set_dynsym_index(-1U); + else + { + sym->set_dynsym_index(index); + ++index; + ++forced_local_count; + dynpool->add(sym->name(), false, NULL); + } + } + *pforced_local_count = forced_local_count; + // Allow a target to set dynsym indexes. if (parameters->target().has_custom_set_dynsym_indexes()) { @@ -2494,6 +2518,8 @@ Symbol_table::set_dynsym_indexes(unsigned int index, ++p) { Symbol* sym = p->second; + if (sym->is_forced_local()) + continue; if (!sym->should_add_dynsym_entry(this)) sym->set_dynsym_index(-1U); else @@ -2510,6 +2536,9 @@ Symbol_table::set_dynsym_indexes(unsigned int index, { Symbol* sym = p->second; + if (sym->is_forced_local()) + continue; + // Note that SYM may already have a dynamic symbol index, since // some symbols appear more than once in the symbol table, with // and without a version. @@ -2581,7 +2610,12 @@ Symbol_table::set_dynsym_indexes(unsigned int index, // Set the final values for all the symbols. The index of the first // global symbol in the output file is *PLOCAL_SYMCOUNT. Record the // file offset OFF. Add their names to POOL. Return the new file -// offset. Update *PLOCAL_SYMCOUNT if necessary. +// offset. Update *PLOCAL_SYMCOUNT if necessary. DYNOFF and +// DYN_GLOBAL_INDEX refer to the start of the symbols that will be +// written from the global symbol table in Symtab::write_globals(), +// which will include forced-local symbols. DYN_GLOBAL_INDEX is +// not necessarily the same as the sh_info field for the .dynsym +// section, which will point to the first real global symbol. off_t Symbol_table::finalize(off_t off, off_t dynoff, size_t dyn_global_index, -- cgit v1.1