From 55a934330a2d2f84e4f972454adda275b02f7aef Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 24 Jan 2008 00:15:00 +0000 Subject: [PATCH] Originally from Craig Silverstein, with changes: support using a version script to force symbols to be local. --- gold/dynobj.cc | 5 +- gold/layout.cc | 4 +- gold/main.cc | 2 +- gold/resolve.cc | 3 + gold/symtab.cc | 355 +++++++++++++++++----------- gold/symtab.h | 61 ++++- gold/testsuite/ver_matching_test.sh | 8 +- gold/testsuite/version_script.map | 2 + 8 files changed, 285 insertions(+), 155 deletions(-) diff --git a/gold/dynobj.cc b/gold/dynobj.cc index 78594a95ae6..898e755d3ad 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -1334,7 +1334,7 @@ Versions::add_def(const Symbol* sym, const char* version, Version_base* const vbnull = NULL; std::pair ins = this->version_table_.insert(std::make_pair(k, vbnull)); - + if (!ins.second) { // We already have an entry for this version. @@ -1344,9 +1344,6 @@ Versions::add_def(const Symbol* sym, const char* version, // weak. gold_assert(vb != NULL); vb->clear_weak(); - - // FIXME: When we support version scripts, we will need to - // check whether this symbol should be forced local. } else { diff --git a/gold/layout.cc b/gold/layout.cc index 9f4c9225e40..38bdcd98e73 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -1291,8 +1291,8 @@ Layout::create_symtab_sections(const Input_objects* input_objects, == this->dynsym_section_->data_size() - locsize); } - off = symtab->finalize(local_symcount, off, dynoff, dyn_global_index, - dyncount, &this->sympool_); + off = symtab->finalize(off, dynoff, dyn_global_index, dyncount, + &this->sympool_, &local_symcount); if (!parameters->strip_all()) { diff --git a/gold/main.cc b/gold/main.cc index 5112223e849..a6c98721805 100644 --- a/gold/main.cc +++ b/gold/main.cc @@ -86,7 +86,7 @@ write_debug_script(std::string filename_str, size_t slash = filename_str.rfind('/'); if (slash != std::string::npos) filename_str = filename_str.c_str() + slash + 1; - filename_str = std::string("/var/tmp/ld-run-") + filename_str + ".sh"; + filename_str = std::string("/tmp/ld-run-") + filename_str + ".sh"; const char* filename = filename_str.c_str(); FILE* fp = fopen(filename, "w"); if (fp) diff --git a/gold/resolve.cc b/gold/resolve.cc index 7062ccc57fe..63ed5e72074 100644 --- a/gold/resolve.cc +++ b/gold/resolve.cc @@ -680,6 +680,7 @@ Symbol::override_base_with_special(const Symbol* from) gold_assert(!from->has_plt_offset_); gold_assert(!from->has_warning_); gold_assert(!from->is_copied_from_dynobj_); + gold_assert(!from->is_forced_local_); } // Override a symbol with a special symbol. @@ -719,6 +720,8 @@ Symbol_table::override_with_special(Sized_symbol* tosym, } while (ssym != tosym); } + if (tosym->binding() == elfcpp::STB_LOCAL) + this->force_local(tosym); } // Instantiate the templates we need. We could use the configure diff --git a/gold/symtab.cc b/gold/symtab.cc index e49178a11f7..7258ae4579e 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -70,6 +70,7 @@ Symbol::init_fields(const char* name, const char* version, this->has_plt_offset_ = false; this->has_warning_ = false; this->is_copied_from_dynobj_ = false; + this->is_forced_local_ = false; } // Return the demangled version of the symbol's name, but only @@ -249,6 +250,10 @@ Symbol::should_add_dynsym_entry() const if (this->needs_dynsym_entry()) return true; + // If the symbol was forced local in a version script, do not add it. + if (this->is_forced_local()) + return false; + // If exporting all symbols or building a shared library, // and the symbol is defined in a regular object and is // externally visible, we need to add it. @@ -298,7 +303,8 @@ Symbol::final_value_is_known() const Symbol_table::Symbol_table(unsigned int count, const Version_script_info& version_script) : saw_undefined_(0), offset_(0), table_(count), namepool_(), - forwarders_(), commons_(), warnings_(), version_script_(version_script) + forwarders_(), commons_(), forced_locals_(), warnings_(), + version_script_(version_script) { namepool_.reserve(count); } @@ -399,6 +405,22 @@ Symbol_table::resolve(Sized_symbol* to, const Sized_symbol* from, to->set_in_dyn(); } +// Record that a symbol is forced to be local by a version script. + +void +Symbol_table::force_local(Symbol* sym) +{ + if (!sym->is_defined() && !sym->is_common()) + return; + if (sym->is_forced_local()) + { + // We already got this one. + return; + } + sym->set_is_forced_local(); + this->forced_locals_.push_back(sym); +} + // Add one symbol from OBJECT to the symbol table. NAME is symbol // name and VERSION is the version; both are canonicalized. DEF is // whether this is the default version. @@ -629,7 +651,9 @@ Symbol_table::add_from_relobj( // this is the default version. const char* ver = strchr(name, '@'); int namelen = 0; + // DEF: is the version default? LOCAL: is the symbol forced local? bool def = false; + bool local = false; if (ver != NULL) { @@ -648,10 +672,14 @@ Symbol_table::add_from_relobj( // the version script may assign a version anyway. namelen = strlen(name); def = true; + // Check the global: entries from the version script. const std::string& version = version_script_.get_symbol_version(name); if (!version.empty()) ver = version.c_str(); + // Check the local: entries from the version script + if (version_script_.symbol_is_local(name)) + local = true; } Sized_symbol* res; @@ -661,6 +689,8 @@ Symbol_table::add_from_relobj( name = this->namepool_.add(name, true, &name_key); res = this->add_from_object(relobj, name, name_key, NULL, 0, false, *psym, sym); + if (local) + this->force_local(res); } else { @@ -919,6 +949,15 @@ Symbol_table::define_special_symbol(const Target* target, const char** pname, bool add_to_table = false; typename Symbol_table_type::iterator add_loc = this->table_.end(); + // If the caller didn't give us a version, see if we get one from + // the version script. + if (*pversion == NULL) + { + const std::string& v(this->version_script_.get_symbol_version(*pname)); + if (!v.empty()) + *pversion = v.c_str(); + } + if (only_if_ref) { oldsym = this->lookup(*pname, *pversion); @@ -1075,7 +1114,12 @@ Symbol_table::do_define_in_output_data( offset_is_from_end); if (oldsym == NULL) - return sym; + { + if (binding == elfcpp::STB_LOCAL + || this->version_script_.symbol_is_local(name)) + this->force_local(sym); + return sym; + } if (Symbol_table::should_override_with_special(oldsym)) this->override_with_special(oldsym, sym); @@ -1171,7 +1215,12 @@ Symbol_table::do_define_in_output_segment( offset_base); if (oldsym == NULL) - return sym; + { + if (binding == elfcpp::STB_LOCAL + || this->version_script_.symbol_is_local(name)) + this->force_local(sym); + return sym; + } if (Symbol_table::should_override_with_special(oldsym)) this->override_with_special(oldsym, sym); @@ -1260,7 +1309,12 @@ Symbol_table::do_define_as_constant( sym->init(name, value, symsize, type, binding, visibility, nonvis); if (oldsym == NULL) - return sym; + { + if (binding == elfcpp::STB_LOCAL + || this->version_script_.symbol_is_local(name)) + this->force_local(sym); + return sym; + } if (Symbol_table::should_override_with_special(oldsym)) this->override_with_special(oldsym, sym); @@ -1423,18 +1477,19 @@ Symbol_table::set_dynsym_indexes(const Target* target, } // Set the final values for all the symbols. The index of the first -// global symbol in the output file is INDEX. Record the file offset -// OFF. Add their names to POOL. Return the new file offset. +// 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. off_t -Symbol_table::finalize(unsigned int index, off_t off, off_t dynoff, - size_t dyn_global_index, size_t dyncount, - Stringpool* pool) +Symbol_table::finalize(off_t off, off_t dynoff, size_t dyn_global_index, + size_t dyncount, Stringpool* pool, + unsigned int *plocal_symcount) { off_t ret; - gold_assert(index != 0); - this->first_global_index_ = index; + gold_assert(*plocal_symcount != 0); + this->first_global_index_ = *plocal_symcount; this->dynamic_offset_ = dynoff; this->first_dynamic_global_index_ = dyn_global_index; @@ -1443,7 +1498,7 @@ Symbol_table::finalize(unsigned int index, off_t off, off_t dynoff, if (parameters->get_size() == 32) { #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_32_LITTLE) - ret = this->sized_finalize<32>(index, off, pool); + ret = this->sized_finalize<32>(off, pool, plocal_symcount); #else gold_unreachable(); #endif @@ -1451,7 +1506,7 @@ Symbol_table::finalize(unsigned int index, off_t off, off_t dynoff, else if (parameters->get_size() == 64) { #if defined(HAVE_TARGET_64_BIG) || defined(HAVE_TARGET_64_LITTLE) - ret = this->sized_finalize<64>(index, off, pool); + ret = this->sized_finalize<64>(off, pool, plocal_symcount); #else gold_unreachable(); #endif @@ -1466,143 +1521,181 @@ Symbol_table::finalize(unsigned int index, off_t off, off_t dynoff, return ret; } +// SYM is going into the symbol table at *PINDEX. Add the name to +// POOL, update *PINDEX and *POFF. + +template +void +Symbol_table::add_to_final_symtab(Symbol* sym, Stringpool* pool, + unsigned int* pindex, off_t* poff) +{ + sym->set_symtab_index(*pindex); + pool->add(sym->name(), false, NULL); + ++*pindex; + *poff += elfcpp::Elf_sizes::sym_size; +} + // Set the final value for all the symbols. This is called after // Layout::finalize, so all the output sections have their final // address. template off_t -Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool) +Symbol_table::sized_finalize(off_t off, Stringpool* pool, + unsigned int* plocal_symcount) { off = align_address(off, size >> 3); this->offset_ = off; - size_t orig_index = index; + unsigned int index = *plocal_symcount; + const unsigned int orig_index = index; - const int sym_size = elfcpp::Elf_sizes::sym_size; + // First do all the symbols which have been forced to be local, as + // they must appear before all global symbols. + 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 (this->sized_finalize_symbol(sym)) + { + this->add_to_final_symtab(sym, pool, &index, &off); + ++*plocal_symcount; + } + } + + // Now do all the remaining symbols. for (Symbol_table_type::iterator p = this->table_.begin(); p != this->table_.end(); ++p) { - Sized_symbol* sym = static_cast*>(p->second); + Symbol* sym = p->second; + if (this->sized_finalize_symbol(sym)) + this->add_to_final_symtab(sym, pool, &index, &off); + } - // FIXME: Here we need to decide which symbols should go into - // the output file, based on --strip. + this->output_count_ = index - orig_index; - // The default version of a symbol may appear twice in the - // symbol table. We only need to finalize it once. - if (sym->has_symtab_index()) - continue; + return off; +} - if (!sym->in_reg()) - { - gold_assert(!sym->has_symtab_index()); - sym->set_symtab_index(-1U); - gold_assert(sym->dynsym_index() == -1U); - continue; - } +// Finalize the symbol SYM. This returns true if the symbol should be +// added to the symbol table, false otherwise. - typename Sized_symbol::Value_type value; +template +bool +Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) +{ + Sized_symbol* sym = static_cast*>(unsized_sym); - switch (sym->source()) - { - case Symbol::FROM_OBJECT: - { - unsigned int shndx = sym->shndx(); + // The default version of a symbol may appear twice in the symbol + // table. We only need to finalize it once. + if (sym->has_symtab_index()) + return false; - // FIXME: We need some target specific support here. - if (shndx >= elfcpp::SHN_LORESERVE - && shndx != elfcpp::SHN_ABS) - { - gold_error(_("%s: unsupported symbol section 0x%x"), - sym->demangled_name().c_str(), shndx); - shndx = elfcpp::SHN_UNDEF; - } + if (!sym->in_reg()) + { + gold_assert(!sym->has_symtab_index()); + sym->set_symtab_index(-1U); + gold_assert(sym->dynsym_index() == -1U); + return false; + } - Object* symobj = sym->object(); - if (symobj->is_dynamic()) - { - value = 0; - shndx = elfcpp::SHN_UNDEF; - } - else if (shndx == elfcpp::SHN_UNDEF) - value = 0; - else if (shndx == elfcpp::SHN_ABS) - value = sym->value(); - else - { - Relobj* relobj = static_cast(symobj); - section_offset_type secoff; - Output_section* os = relobj->output_section(shndx, &secoff); + typename Sized_symbol::Value_type value; - if (os == NULL) - { - sym->set_symtab_index(-1U); - gold_assert(sym->dynsym_index() == -1U); - continue; - } + switch (sym->source()) + { + case Symbol::FROM_OBJECT: + { + unsigned int shndx = sym->shndx(); - if (sym->type() == elfcpp::STT_TLS) - value = sym->value() + os->tls_offset() + secoff; - else - value = sym->value() + os->address() + secoff; - } + // FIXME: We need some target specific support here. + if (shndx >= elfcpp::SHN_LORESERVE + && shndx != elfcpp::SHN_ABS) + { + gold_error(_("%s: unsupported symbol section 0x%x"), + sym->demangled_name().c_str(), shndx); + shndx = elfcpp::SHN_UNDEF; } - break; - case Symbol::IN_OUTPUT_DATA: + Object* symobj = sym->object(); + if (symobj->is_dynamic()) { - Output_data* od = sym->output_data(); - value = sym->value() + od->address(); - if (sym->offset_is_from_end()) - value += od->data_size(); + value = 0; + shndx = elfcpp::SHN_UNDEF; } - break; - - case Symbol::IN_OUTPUT_SEGMENT: + else if (shndx == elfcpp::SHN_UNDEF) + value = 0; + else if (shndx == elfcpp::SHN_ABS) + value = sym->value(); + else { - Output_segment* os = sym->output_segment(); - value = sym->value() + os->vaddr(); - switch (sym->offset_base()) + Relobj* relobj = static_cast(symobj); + section_offset_type secoff; + Output_section* os = relobj->output_section(shndx, &secoff); + + if (os == NULL) { - case Symbol::SEGMENT_START: - break; - case Symbol::SEGMENT_END: - value += os->memsz(); - break; - case Symbol::SEGMENT_BSS: - value += os->filesz(); - break; - default: - gold_unreachable(); + sym->set_symtab_index(-1U); + gold_assert(sym->dynsym_index() == -1U); + return false; } + + if (sym->type() == elfcpp::STT_TLS) + value = sym->value() + os->tls_offset() + secoff; + else + value = sym->value() + os->address() + secoff; } - break; + } + break; + + case Symbol::IN_OUTPUT_DATA: + { + Output_data* od = sym->output_data(); + value = sym->value() + od->address(); + if (sym->offset_is_from_end()) + value += od->data_size(); + } + break; + + case Symbol::IN_OUTPUT_SEGMENT: + { + Output_segment* os = sym->output_segment(); + value = sym->value() + os->vaddr(); + switch (sym->offset_base()) + { + case Symbol::SEGMENT_START: + break; + case Symbol::SEGMENT_END: + value += os->memsz(); + break; + case Symbol::SEGMENT_BSS: + value += os->filesz(); + break; + default: + gold_unreachable(); + } + } + break; - case Symbol::CONSTANT: - value = sym->value(); - break; + case Symbol::CONSTANT: + value = sym->value(); + break; - default: - gold_unreachable(); - } + default: + gold_unreachable(); + } - sym->set_value(value); + sym->set_value(value); - if (parameters->strip_all()) - sym->set_symtab_index(-1U); - else - { - sym->set_symtab_index(index); - pool->add(sym->name(), false, NULL); - ++index; - off += sym_size; - } + if (parameters->strip_all()) + { + sym->set_symtab_index(-1U); + return false; } - this->output_count_ = index - orig_index; - - return off; + return true; } // Write out the global symbols. @@ -1670,20 +1763,22 @@ Symbol_table::sized_write_globals(const Input_objects* input_objects, const Target* const target = input_objects->target(); const int sym_size = elfcpp::Elf_sizes::sym_size; - unsigned int index = this->first_global_index_; - const off_t oview_size = this->output_count_ * sym_size; + + const unsigned int output_count = this->output_count_; + const section_size_type oview_size = output_count * sym_size; + const unsigned int first_global_index = this->first_global_index_; unsigned char* const psyms = of->get_output_view(this->offset_, oview_size); - unsigned int dynamic_count = this->dynamic_count_; - off_t dynamic_size = dynamic_count * sym_size; - unsigned int first_dynamic_global_index = this->first_dynamic_global_index_; + const unsigned int dynamic_count = this->dynamic_count_; + const section_size_type dynamic_size = dynamic_count * sym_size; + const unsigned int first_dynamic_global_index = + this->first_dynamic_global_index_; unsigned char* dynamic_view; if (this->dynamic_offset_ == 0) dynamic_view = NULL; else dynamic_view = of->get_output_view(this->dynamic_offset_, dynamic_size); - unsigned char* ps = psyms; for (Symbol_table_type::const_iterator p = this->table_.begin(); p != this->table_.end(); ++p) @@ -1706,18 +1801,6 @@ Symbol_table::sized_write_globals(const Input_objects* input_objects, continue; } - if (sym_index == index) - ++index; - else if (sym_index != -1U) - { - // We have already seen this symbol, because it has a - // default version. - gold_assert(sym_index < index); - if (dynsym_index == -1U) - continue; - sym_index = -1U; - } - unsigned int shndx; typename elfcpp::Elf_types<32>::Elf_Addr value = sym->value(); switch (sym->source()) @@ -1777,10 +1860,12 @@ Symbol_table::sized_write_globals(const Input_objects* input_objects, if (sym_index != -1U) { + sym_index -= first_global_index; + gold_assert(sym_index < output_count); + unsigned char* ps = psyms + (sym_index * sym_size); this->sized_write_symbol SELECT_SIZE_ENDIAN_NAME(size, big_endian) ( sym, sym->value(), shndx, sympool, ps SELECT_SIZE_ENDIAN(size, big_endian)); - ps += sym_size; } if (dynsym_index != -1U) @@ -1794,8 +1879,6 @@ Symbol_table::sized_write_globals(const Input_objects* input_objects, } } - gold_assert(ps - psyms == oview_size); - of->write_output_view(this->offset_, oview_size, psyms); if (dynamic_view != NULL) of->write_output_view(this->dynamic_offset_, dynamic_size, dynamic_view); @@ -1818,7 +1901,11 @@ Symbol_table::sized_write_symbol( osym.put_st_name(pool->get_offset(sym->name())); osym.put_st_value(value); osym.put_st_size(sym->symsize()); - osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type())); + // A version script may have overridden the default binding. + if (sym->is_forced_local()) + osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL, sym->type())); + else + osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type())); osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->nonvis())); osym.put_st_shndx(shndx); } diff --git a/gold/symtab.h b/gold/symtab.h index d3e076bc9c1..8110e4aebed 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -466,6 +466,7 @@ class Symbol return (this->visibility_ != elfcpp::STV_INTERNAL && this->visibility_ != elfcpp::STV_HIDDEN && this->visibility_ != elfcpp::STV_PROTECTED + && !this->is_forced_local_ && parameters->output_is_shared() && !parameters->symbolic()); } @@ -581,6 +582,17 @@ class Symbol set_is_copied_from_dynobj() { this->is_copied_from_dynobj_ = true; } + // Return whether this symbol is forced to visibility STB_LOCAL + // by a "local:" entry in a version script. + bool + is_forced_local() const + { return this->is_forced_local_; } + + // Mark this symbol as forced to STB_LOCAL visibility. + void + set_is_forced_local() + { this->is_forced_local_ = true; } + protected: // Instances of this class should always be created at a specific // size. @@ -757,6 +769,9 @@ class Symbol // True if we are using a COPY reloc for this symbol, so that the // real definition lives in a dynamic object. bool is_copied_from_dynobj_ : 1; + // True if this symbol was forced to local visibility by a version + // script. + bool is_forced_local_ : 1; }; // The parts of a symbol which are size specific. Using a template @@ -1132,15 +1147,17 @@ class Symbol_table // Finalize the symbol table after we have set the final addresses // of all the input sections. This sets the final symbol indexes, - // values and adds the names to *POOL. INDEX is the index of the - // first global symbol. OFF is the file offset of the global symbol - // table, DYNOFF is the offset of the globals in the dynamic symbol - // table, DYN_GLOBAL_INDEX is the index of the first global dynamic - // symbol, and DYNCOUNT is the number of global dynamic symbols. - // This records the parameters, and returns the new file offset. + // values and adds the names to *POOL. *PLOCAL_SYMCOUNT is the + // index of the first global symbol. OFF is the file offset of the + // global symbol table, DYNOFF is the offset of the globals in the + // dynamic symbol table, DYN_GLOBAL_INDEX is the index of the first + // global dynamic symbol, and DYNCOUNT is the number of global + // dynamic symbols. This records the parameters, and returns the + // new file offset. It updates *PLOCAL_SYMCOUNT if it created any + // local symbols. off_t - finalize(unsigned int index, off_t off, off_t dynoff, - size_t dyn_global_index, size_t dyncount, Stringpool* pool); + finalize(off_t off, off_t dynoff, size_t dyn_global_index, size_t dyncount, + Stringpool* pool, unsigned int *plocal_symcount); // Write out the global symbols. void @@ -1189,6 +1206,10 @@ class Symbol_table resolve(Sized_symbol* to, const Sized_symbol* from, const char* version ACCEPT_SIZE_ENDIAN); + // Record that a symbol is forced to be local by a version script. + void + force_local(Symbol*); + // Whether we should override a symbol, based on flags in // resolve.cc. static bool @@ -1270,7 +1291,18 @@ class Symbol_table // Finalize symbols specialized for size. template off_t - sized_finalize(unsigned int, off_t, Stringpool*); + sized_finalize(off_t, Stringpool*, unsigned int*); + + // Finalize a symbol. Return whether it should be added to the + // symbol table. + template + bool + sized_finalize_symbol(Symbol*); + + // Add a symbol the final symtab by setting its index. + template + void + add_to_final_symtab(Symbol*, Stringpool*, unsigned int* pindex, off_t* poff); // Write globals specialized for size and endianness. template @@ -1318,6 +1350,9 @@ class Symbol_table // The type of the list of common symbols. typedef std::vector Commons_type; + // The type of the list of symbols which have been forced local. + typedef std::vector Forced_locals; + // A map from symbols with COPY relocs to the dynamic objects where // they are defined. typedef Unordered_map Copied_symbol_dynobjs; @@ -1358,13 +1393,13 @@ class Symbol_table // write the table. off_t offset_; // The number of global symbols we want to write out. - size_t output_count_; + unsigned int output_count_; // The file offset of the global dynamic symbols, or 0 if none. off_t dynamic_offset_; // The index of the first global dynamic symbol. unsigned int first_dynamic_global_index_; // The number of global dynamic symbols, or 0 if none. - off_t dynamic_count_; + unsigned int dynamic_count_; // The symbol hash table. Symbol_table_type table_; // A pool of symbol names. This is used for all global symbols. @@ -1381,6 +1416,10 @@ class Symbol_table // symbol is no longer a common symbol. It may also have become a // forwarder. Commons_type commons_; + // A list of symbols which have been forced to be local. We don't + // expect there to be very many of them, so we keep a list of them + // rather than walking the whole table to find them. + Forced_locals forced_locals_; // Manage symbol warnings. Warnings warnings_; // Manage potential One Definition Rule (ODR) violations. diff --git a/gold/testsuite/ver_matching_test.sh b/gold/testsuite/ver_matching_test.sh index 2ecdd98d280..7f425266100 100755 --- a/gold/testsuite/ver_matching_test.sh +++ b/gold/testsuite/ver_matching_test.sh @@ -79,8 +79,10 @@ check ver_matching_test.stdout "V1 *baz(int\\*)$" check_missing ver_matching_test.stdout "V1 *baz(int\\*, char)$" check_missing ver_matching_test.stdout "V1 *baz(char\\*, int)$" -# TODO: foo1 should be a local symbol and not show up in the .dynsym -# dump, but we haven't figured out how to suppress it yet. -# check_missing ver_matching_test.stdout "foo1" +check_missing ver_matching_test.stdout "foo1" + +# This symbols is injected by the linker itself, but should still +# follow local: +check_missing ver_matching_test.stdout "__bss_start" exit 0 diff --git a/gold/testsuite/version_script.map b/gold/testsuite/version_script.map index c7662af8d3c..e9106102d46 100644 --- a/gold/testsuite/version_script.map +++ b/gold/testsuite/version_script.map @@ -30,4 +30,6 @@ V2 { }; blaz*; foo; + local: + _[^A-Z]*; } V1; -- 2.30.2