X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gold%2Fdynobj.cc;h=ac0c321c7a44427459de6c77118b36425191d7df;hb=fad072ac13b347994507f32882b557ab7b044a19;hp=9247a79d7d51484dbef7f32dbae58ae93a2a0f52;hpb=92de84a60cbdb80b808c8571e709c1384c6ee6fc;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/dynobj.cc b/gold/dynobj.cc index 9247a79d7d..ac0c321c7a 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -1,6 +1,6 @@ // dynobj.cc -- dynamic object support for gold -// Copyright 2006, 2007, 2008 Free Software Foundation, Inc. +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -49,16 +49,23 @@ Dynobj::Dynobj(const std::string& name, Input_file* input_file, off_t offset) // object's filename. The only exception is when the dynamic object // is part of an archive (so the filename is the archive's // filename). In that case, we use just the dynobj's name-in-archive. - this->soname_ = this->input_file()->found_name(); - if (this->offset() != 0) + if (input_file == NULL) + this->soname_ = name; + else { - std::string::size_type open_paren = this->name().find('('); - std::string::size_type close_paren = this->name().find(')'); - if (open_paren != std::string::npos && close_paren != std::string::npos) + this->soname_ = input_file->found_name(); + if (this->offset() != 0) { - // It's an archive, and name() is of the form 'foo.a(bar.so)'. - this->soname_ = this->name().substr(open_paren + 1, - close_paren - (open_paren + 1)); + std::string::size_type open_paren = this->name().find('('); + std::string::size_type close_paren = this->name().find(')'); + if (open_paren != std::string::npos + && close_paren != std::string::npos) + { + // It's an archive, and name() is of the form 'foo.a(bar.so)'. + open_paren += 1; + this->soname_ = this->name().substr(open_paren, + close_paren - open_paren); + } } } } @@ -83,13 +90,8 @@ Sized_dynobj::Sized_dynobj( template void -Sized_dynobj::setup( - const elfcpp::Ehdr& ehdr) +Sized_dynobj::setup() { - this->set_target(ehdr.get_e_machine(), size, big_endian, - ehdr.get_e_ident()[elfcpp::EI_OSABI], - ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]); - const unsigned int shnum = this->elf_file_.shnum(); this->set_shnum(shnum); } @@ -111,6 +113,7 @@ Sized_dynobj::find_dynsym_sections( *pverneed_shndx = -1U; *pdynamic_shndx = -1U; + unsigned int symtab_shndx = 0; unsigned int xindex_shndx = 0; unsigned int xindex_link = 0; const unsigned int shnum = this->shnum(); @@ -133,6 +136,10 @@ Sized_dynobj::find_dynsym_sections( } pi = NULL; break; + case elfcpp::SHT_SYMTAB: + symtab_shndx = i; + pi = NULL; + break; case elfcpp::SHT_GNU_versym: pi = pversym_shndx; break; @@ -171,6 +178,25 @@ Sized_dynobj::find_dynsym_sections( *pi = i; } + + // If there is no dynamic symbol table, use the normal symbol table. + // On some SVR4 systems, a shared library is stored in an archive. + // The version stored in the archive only has a normal symbol table. + // It has an SONAME entry which points to another copy in the file + // system which has a dynamic symbol table as usual. This is way of + // addressing the issues which glibc addresses using GROUP with + // libc_nonshared.a. + if (this->dynsym_shndx_ == -1U && symtab_shndx != 0) + { + this->dynsym_shndx_ = symtab_shndx; + if (xindex_shndx > 0 && xindex_link == symtab_shndx) + { + Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset()); + xindex->read_symtab_xindex(this, xindex_shndx, + pshdrs); + this->set_xindex(xindex); + } + } } // Read the contents of section SHNDX. PSHDRS points to the section @@ -328,13 +354,20 @@ Sized_dynobj::do_read_symbols(Read_symbols_data* sd) sd->external_symbols_offset = 0; sd->symbol_names = NULL; sd->symbol_names_size = 0; + sd->versym = NULL; + sd->versym_size = 0; + sd->verdef = NULL; + sd->verdef_size = 0; + sd->verdef_info = 0; + sd->verneed = NULL; + sd->verneed_size = 0; + sd->verneed_info = 0; if (this->dynsym_shndx_ != -1U) { // Get the dynamic symbols. typename This::Shdr dynsymshdr(pshdrs + this->dynsym_shndx_ * This::shdr_size); - gold_assert(dynsymshdr.get_sh_type() == elfcpp::SHT_DYNSYM); sd->symbols = this->get_lasting_view(dynsymshdr.get_sh_offset(), dynsymshdr.get_sh_size(), true, @@ -413,7 +446,7 @@ Sized_dynobj::do_initialize_xindex() // Lay out the input sections for a dynamic object. We don't want to // include sections from a dynamic object, so all that we actually do -// here is check for .gnu.warning sections. +// here is check for .gnu.warning and .note.GNU-split-stack sections. template void @@ -448,6 +481,7 @@ Sized_dynobj::do_layout(Symbol_table* symtab, const char* name = pnames + shdr.get_sh_name(); this->handle_gnu_warning_section(name, i, symtab); + this->handle_split_stack_section(name); } delete sd->section_headers; @@ -655,7 +689,8 @@ Sized_dynobj::make_version_map( template void Sized_dynobj::do_add_symbols(Symbol_table* symtab, - Read_symbols_data* sd) + Read_symbols_data* sd, + Layout*) { if (sd->symbols == NULL) { @@ -677,9 +712,11 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, Version_map version_map; this->make_version_map(sd, &version_map); - // If printing symbol counts, we want to track symbols. - - if (parameters->options().user_set_print_symbol_counts()) + // If printing symbol counts or a cross reference table or + // preparing for an incremental link, we want to track symbols. + if (parameters->options().user_set_print_symbol_counts() + || parameters->options().cref() + || parameters->incremental()) { this->symbols_ = new Symbols(); this->symbols_->resize(symcount); @@ -722,6 +759,52 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, this->clear_view_cache_marks(); } +template +Archive::Should_include +Sized_dynobj::do_should_include_member(Symbol_table*, + Layout*, + Read_symbols_data*, + std::string*) +{ + return Archive::SHOULD_INCLUDE_YES; +} + +// Iterate over global symbols, calling a visitor class V for each. + +template +void +Sized_dynobj::do_for_all_global_symbols( + Read_symbols_data* sd, + Library_base::Symbol_visitor_base* v) +{ + const char* sym_names = + reinterpret_cast(sd->symbol_names->data()); + const unsigned char* syms = + sd->symbols->data() + sd->external_symbols_offset; + const int sym_size = elfcpp::Elf_sizes::sym_size; + size_t symcount = ((sd->symbols_size - sd->external_symbols_offset) + / sym_size); + const unsigned char* p = syms; + + for (size_t i = 0; i < symcount; ++i, p += sym_size) + { + elfcpp::Sym sym(p); + if (sym.get_st_shndx() != elfcpp::SHN_UNDEF + && sym.get_st_bind() != elfcpp::STB_LOCAL) + v->visit(sym_names + sym.get_st_name()); + } +} + +// Iterate over local symbols, calling a visitor class V for each GOT offset +// associated with a local symbol. + +template +void +Sized_dynobj::do_for_all_local_got_entries( + Got_offset_list::Visitor*) const +{ +} + // Get symbol counts. template @@ -740,7 +823,7 @@ Sized_dynobj::do_get_global_symbol_counts( && (*p)->source() == Symbol::FROM_OBJECT && (*p)->object() == this && (*p)->is_defined() - && (*p)->dynsym_index() != -1U) + && (*p)->has_dynsym_index()) ++count; *used = count; } @@ -954,9 +1037,10 @@ Dynobj::create_gnu_hash_table(const std::vector& dynsyms, { Symbol* sym = dynsyms[i]; - // FIXME: Should put on unhashed_dynsyms if the symbol is - // hidden. - if (sym->is_undefined()) + if (!sym->needs_dynsym_value() + && (sym->is_undefined() + || sym->is_from_dynobj() + || sym->is_forced_local())) unhashed_dynsyms.push_back(sym); else { @@ -1191,7 +1275,8 @@ Verdef::write(const Stringpool* dynpool, bool is_last, unsigned char* pb) const elfcpp::Verdef_write vd(pb); vd.set_vd_version(elfcpp::VER_DEF_CURRENT); vd.set_vd_flags((this->is_base_ ? elfcpp::VER_FLG_BASE : 0) - | (this->is_weak_ ? elfcpp::VER_FLG_WEAK : 0)); + | (this->is_weak_ ? elfcpp::VER_FLG_WEAK : 0) + | (this->is_info_ ? elfcpp::VER_FLG_INFO : 0)); vd.set_vd_ndx(this->index()); vd.set_vd_cnt(1 + this->deps_.size()); vd.set_vd_hash(Dynobj::elf_hash(this->name())); @@ -1303,28 +1388,18 @@ Verneed::write(const Stringpool* dynpool, bool is_last, Versions::Versions(const Version_script_info& version_script, Stringpool* dynpool) : defs_(), needs_(), version_table_(), - is_finalized_(false), version_script_(version_script) + is_finalized_(false), version_script_(version_script), + needs_base_version_(parameters->options().shared()) { - // We always need a base version, so define that first. Nothing - // explicitly declares itself as part of base, so it doesn't need to - // be in version_table_. - // FIXME: Should use soname here when creating a shared object. Is - // this fixme still valid? It looks like it's doing the right thing - // to me. - if (parameters->options().shared()) - { - const char* name = dynpool->add(parameters->options().output_file_name(), - false, NULL); - Verdef* vdbase = new Verdef(name, std::vector(), - true, false, true); - this->defs_.push_back(vdbase); - } - if (!this->version_script_.empty()) { // Parse the version script, and insert each declared version into // defs_ and version_table_. std::vector versions = this->version_script_.get_versions(); + + if (this->needs_base_version_ && !versions.empty()) + this->define_base_version(dynpool); + for (size_t k = 0; k < versions.size(); ++k) { Stringpool::Key version_key; @@ -1333,7 +1408,7 @@ Versions::Versions(const Version_script_info& version_script, Verdef* const vd = new Verdef( version, this->version_script_.get_dependencies(version), - false, false, false); + false, false, false, false); this->defs_.push_back(vd); Key key(version_key, 0); this->version_table_.insert(std::make_pair(key, vd)); @@ -1354,6 +1429,28 @@ Versions::~Versions() delete *p; } +// Define the base version of a shared library. The base version definition +// must be the first entry in defs_. We insert it lazily so that defs_ is +// empty if no symbol versioning is used. Then layout can just drop the +// version sections. + +void +Versions::define_base_version(Stringpool* dynpool) +{ + // If we do any versioning at all, we always need a base version, so + // define that first. Nothing explicitly declares itself as part of base, + // so it doesn't need to be in version_table_. + gold_assert(this->defs_.empty()); + const char* name = parameters->options().soname(); + if (name == NULL) + name = parameters->options().output_file_name(); + name = dynpool->add(name, false, NULL); + Verdef* vdbase = new Verdef(name, std::vector(), + true, false, false, true); + this->defs_.push_back(vdbase); + this->needs_base_version_ = false; +} + // Return the dynamic object which a symbol refers to. Dynobj* @@ -1386,7 +1483,7 @@ Versions::record_version(const Symbol_table* symtab, if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj()) { if (parameters->options().shared()) - this->add_def(sym, version, version_key); + this->add_def(dynpool, sym, version, version_key); } else { @@ -1399,7 +1496,7 @@ Versions::record_version(const Symbol_table* symtab, // We've found a symbol SYM defined in version VERSION. void -Versions::add_def(const Symbol* sym, const char* version, +Versions::add_def(Stringpool* dynpool, const Symbol* sym, const char* version, Stringpool::Key version_key) { Key k(version_key, 0); @@ -1423,13 +1520,20 @@ Versions::add_def(const Symbol* sym, const char* version, // find a definition of a symbol with a version which is not // in the version script. if (parameters->options().shared()) - gold_error(_("symbol %s has undefined version %s"), - sym->demangled_name().c_str(), version); - + { + gold_error(_("symbol %s has undefined version %s"), + sym->demangled_name().c_str(), version); + if (this->needs_base_version_) + this->define_base_version(dynpool); + } + else + // We only insert a base version for shared library. + gold_assert(!this->needs_base_version_); + // When creating a regular executable, automatically define // a new version. Verdef* vd = new Verdef(version, std::vector(), - false, false, false); + false, false, false, false); this->defs_.push_back(vd); ins.first->second = vd; } @@ -1472,6 +1576,10 @@ Versions::add_need(Stringpool* dynpool, const char* filename, const char* name, if (vn == NULL) { + // Create base version definition lazily for shared library. + if (this->needs_base_version_) + this->define_base_version(dynpool); + // We have a new filename. vn = new Verneed(filename); this->needs_.push_back(vn); @@ -1502,13 +1610,16 @@ Versions::finalize(Symbol_table* symtab, unsigned int dynsym_index, if (!(*p)->is_symbol_created()) { Symbol* vsym = symtab->define_as_constant((*p)->name(), - (*p)->name(), 0, 0, + (*p)->name(), + Symbol_table::PREDEFINED, + 0, 0, elfcpp::STT_OBJECT, elfcpp::STB_GLOBAL, elfcpp::STV_DEFAULT, 0, false, false); vsym->set_needs_dynsym_entry(); vsym->set_dynsym_index(dynsym_index); + vsym->set_is_default(); ++dynsym_index; syms->push_back(vsym); // The name is already in the dynamic pool. @@ -1598,10 +1709,15 @@ Versions::symbol_section_contents(const Symbol_table* symtab, { unsigned int version_index; const char* version = (*p)->version(); - if (version == NULL) - version_index = elfcpp::VER_NDX_GLOBAL; - else + if (version != NULL) version_index = this->version_index(symtab, dynpool, *p); + else + { + if ((*p)->is_defined() && !(*p)->is_from_dynobj()) + version_index = elfcpp::VER_NDX_GLOBAL; + else + version_index = elfcpp::VER_NDX_LOCAL; + } // If the symbol was defined as foo@V1 instead of foo@@V1, add // the hidden bit. if ((*p)->version() != NULL && !(*p)->is_default()) @@ -1663,8 +1779,8 @@ Versions::def_section_contents(const Stringpool* dynpool, template void Versions::need_section_contents(const Stringpool* dynpool, - unsigned char** pp, unsigned int *psize, - unsigned int *pentries) const + unsigned char** pp, unsigned int* psize, + unsigned int* pentries) const { gold_assert(this->is_finalized_); gold_assert(!this->needs_.empty());