X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gold%2Fdynobj.cc;h=0a8d897c65ce754c73afada6f0096ecd4f7ae87b;hb=0394eed15c5bf24943850f356785152c3d65ab94;hp=2bf2373b846cb493fbe2a27e55a905e55881dd87;hpb=75f2446ec3c13eca3fe0c7cfdbb232e760d36596;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/dynobj.cc b/gold/dynobj.cc index 2bf2373b84..0a8d897c65 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -1,6 +1,6 @@ // dynobj.cc -- dynamic object support for gold -// Copyright 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2006-2019 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -27,6 +27,7 @@ #include "elfcpp.h" #include "parameters.h" +#include "script.h" #include "symtab.h" #include "dynobj.h" @@ -35,14 +36,38 @@ namespace gold // Class Dynobj. -// Return the string to use in a DT_NEEDED entry. +// Sets up the default soname_ to use, in the (rare) cases we never +// see a DT_SONAME entry. -const char* -Dynobj::soname() const +Dynobj::Dynobj(const std::string& name, Input_file* input_file, off_t offset) + : Object(name, input_file, true, offset), + needed_(), + unknown_needed_(UNKNOWN_NEEDED_UNSET) { - if (!this->soname_.empty()) - return this->soname_.c_str(); - return this->input_file()->found_name().c_str(); + // This will be overridden by a DT_SONAME entry, hopefully. But if + // we never see a DT_SONAME entry, our rule is to use the dynamic + // 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. + if (input_file == NULL) + this->soname_ = name; + else + { + this->soname_ = input_file->found_name(); + if (this->offset() != 0) + { + 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); + } + } + } } // Class Sized_dynobj. @@ -54,7 +79,10 @@ Sized_dynobj::Sized_dynobj( off_t offset, const elfcpp::Ehdr& ehdr) : Dynobj(name, input_file, offset), - elf_file_(this, ehdr) + elf_file_(this, ehdr), + dynsym_shndx_(-1U), + symbols_(NULL), + defined_count_(0) { } @@ -62,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); } @@ -80,18 +103,19 @@ template void Sized_dynobj::find_dynsym_sections( const unsigned char* pshdrs, - unsigned int* pdynsym_shndx, unsigned int* pversym_shndx, unsigned int* pverdef_shndx, unsigned int* pverneed_shndx, unsigned int* pdynamic_shndx) { - *pdynsym_shndx = -1U; *pversym_shndx = -1U; *pverdef_shndx = -1U; *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(); const unsigned char* p = pshdrs; for (unsigned int i = 0; i < shnum; ++i, p += This::shdr_size) @@ -102,7 +126,19 @@ Sized_dynobj::find_dynsym_sections( switch (shdr.get_sh_type()) { case elfcpp::SHT_DYNSYM: - pi = pdynsym_shndx; + this->dynsym_shndx_ = i; + if (xindex_shndx > 0 && xindex_link == i) + { + Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset()); + xindex->read_symtab_xindex(this, xindex_shndx, + pshdrs); + this->set_xindex(xindex); + } + pi = NULL; + break; + case elfcpp::SHT_SYMTAB: + symtab_shndx = i; + pi = NULL; break; case elfcpp::SHT_GNU_versym: pi = pversym_shndx; @@ -116,6 +152,18 @@ Sized_dynobj::find_dynsym_sections( case elfcpp::SHT_DYNAMIC: pi = pdynamic_shndx; break; + case elfcpp::SHT_SYMTAB_SHNDX: + xindex_shndx = i; + xindex_link = this->adjust_shndx(shdr.get_sh_link()); + if (xindex_link == this->dynsym_shndx_) + { + Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset()); + xindex->read_symtab_xindex(this, xindex_shndx, + pshdrs); + this->set_xindex(xindex); + } + pi = NULL; + break; default: pi = NULL; break; @@ -130,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 @@ -145,7 +212,7 @@ Sized_dynobj::read_dynsym_section( elfcpp::SHT type, unsigned int link, File_view** view, - off_t* view_size, + section_size_type* view_size, unsigned int* view_info) { if (shndx == -1U) @@ -160,38 +227,39 @@ Sized_dynobj::read_dynsym_section( gold_assert(shdr.get_sh_type() == type); - if (shdr.get_sh_link() != link) + if (this->adjust_shndx(shdr.get_sh_link()) != link) this->error(_("unexpected link in section %u header: %u != %u"), - shndx, shdr.get_sh_link(), link); + shndx, this->adjust_shndx(shdr.get_sh_link()), link); *view = this->get_lasting_view(shdr.get_sh_offset(), shdr.get_sh_size(), - false); - *view_size = shdr.get_sh_size(); + true, false); + *view_size = convert_to_section_size_type(shdr.get_sh_size()); *view_info = shdr.get_sh_info(); } -// Set the soname field if this shared object has a DT_SONAME tag. -// PSHDRS points to the section headers. DYNAMIC_SHNDX is the section -// index of the SHT_DYNAMIC section. STRTAB_SHNDX, STRTAB, and -// STRTAB_SIZE are the section index and contents of a string table -// which may be the one associated with the SHT_DYNAMIC section. +// Read the dynamic tags. Set the soname field if this shared object +// has a DT_SONAME tag. Record the DT_NEEDED tags. PSHDRS points to +// the section headers. DYNAMIC_SHNDX is the section index of the +// SHT_DYNAMIC section. STRTAB_SHNDX, STRTAB, and STRTAB_SIZE are the +// section index and contents of a string table which may be the one +// associated with the SHT_DYNAMIC section. template void -Sized_dynobj::set_soname(const unsigned char* pshdrs, - unsigned int dynamic_shndx, - unsigned int strtab_shndx, - const unsigned char* strtabu, - off_t strtab_size) +Sized_dynobj::read_dynamic(const unsigned char* pshdrs, + unsigned int dynamic_shndx, + unsigned int strtab_shndx, + const unsigned char* strtabu, + off_t strtab_size) { typename This::Shdr dynamicshdr(pshdrs + dynamic_shndx * This::shdr_size); gold_assert(dynamicshdr.get_sh_type() == elfcpp::SHT_DYNAMIC); const off_t dynamic_size = dynamicshdr.get_sh_size(); const unsigned char* pdynamic = this->get_view(dynamicshdr.get_sh_offset(), - dynamic_size, false); + dynamic_size, true, false); - const unsigned int link = dynamicshdr.get_sh_link(); + const unsigned int link = this->adjust_shndx(dynamicshdr.get_sh_link()); if (link != strtab_shndx) { if (link >= this->shnum()) @@ -210,33 +278,52 @@ Sized_dynobj::set_soname(const unsigned char* pshdrs, } strtab_size = strtabshdr.get_sh_size(); - strtabu = this->get_view(strtabshdr.get_sh_offset(), strtab_size, false); + strtabu = this->get_view(strtabshdr.get_sh_offset(), strtab_size, false, + false); } + const char* const strtab = reinterpret_cast(strtabu); + for (const unsigned char* p = pdynamic; p < pdynamic + dynamic_size; p += This::dyn_size) { typename This::Dyn dyn(p); - if (dyn.get_d_tag() == elfcpp::DT_SONAME) + switch (dyn.get_d_tag()) { - off_t val = dyn.get_d_val(); - if (val >= strtab_size) - { + case elfcpp::DT_NULL: + // We should always see DT_NULL at the end of the dynamic + // tags. + return; + + case elfcpp::DT_SONAME: + { + off_t val = dyn.get_d_val(); + if (val >= strtab_size) this->error(_("DT_SONAME value out of range: %lld >= %lld"), - static_cast(val), - static_cast(strtab_size)); - return; - } + static_cast(val), + static_cast(strtab_size)); + else + this->set_soname_string(strtab + val); + } + break; - const char* strtab = reinterpret_cast(strtabu); - this->set_soname_string(strtab + val); - return; - } + case elfcpp::DT_NEEDED: + { + off_t val = dyn.get_d_val(); + if (val >= strtab_size) + this->error(_("DT_NEEDED value out of range: %lld >= %lld"), + static_cast(val), + static_cast(strtab_size)); + else + this->add_needed(strtab + val); + } + break; - if (dyn.get_d_tag() == elfcpp::DT_NULL) - return; + default: + break; + } } this->error(_("missing DT_NULL in dynamic segment")); @@ -248,38 +335,70 @@ Sized_dynobj::set_soname(const unsigned char* pshdrs, template void Sized_dynobj::do_read_symbols(Read_symbols_data* sd) +{ + this->base_read_symbols(sd); +} + +// Read the symbols and sections from a dynamic object. We read the +// dynamic symbols, not the normal symbols. This is common code for +// all target-specific overrides of do_read_symbols(). + +template +void +Sized_dynobj::base_read_symbols(Read_symbols_data* sd) { this->read_section_data(&this->elf_file_, sd); const unsigned char* const pshdrs = sd->section_headers->data(); - unsigned int dynsym_shndx; unsigned int versym_shndx; unsigned int verdef_shndx; unsigned int verneed_shndx; unsigned int dynamic_shndx; - this->find_dynsym_sections(pshdrs, &dynsym_shndx, &versym_shndx, - &verdef_shndx, &verneed_shndx, &dynamic_shndx); + this->find_dynsym_sections(pshdrs, &versym_shndx, &verdef_shndx, + &verneed_shndx, &dynamic_shndx); unsigned int strtab_shndx = -1U; sd->symbols = NULL; sd->symbols_size = 0; + 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; + + const unsigned char* namesu = sd->section_names->data(); + const char* names = reinterpret_cast(namesu); + if (memmem(names, sd->section_names_size, ".zdebug_", 8) != NULL) + { + Compressed_section_map* compressed_sections = + build_compressed_section_map( + pshdrs, this->shnum(), names, sd->section_names_size, this, true); + if (compressed_sections != NULL) + this->set_compressed_sections(compressed_sections); + } - if (dynsym_shndx != -1U) + if (this->dynsym_shndx_ != -1U) { // Get the dynamic symbols. - typename This::Shdr dynsymshdr(pshdrs + dynsym_shndx * This::shdr_size); - gold_assert(dynsymshdr.get_sh_type() == elfcpp::SHT_DYNSYM); + typename This::Shdr dynsymshdr(pshdrs + + this->dynsym_shndx_ * This::shdr_size); sd->symbols = this->get_lasting_view(dynsymshdr.get_sh_offset(), - dynsymshdr.get_sh_size(), false); - sd->symbols_size = dynsymshdr.get_sh_size(); + dynsymshdr.get_sh_size(), true, + false); + sd->symbols_size = + convert_to_section_size_type(dynsymshdr.get_sh_size()); // Get the symbol names. - strtab_shndx = dynsymshdr.get_sh_link(); + strtab_shndx = this->adjust_shndx(dynsymshdr.get_sh_link()); if (strtab_shndx >= this->shnum()) { this->error(_("invalid dynamic symbol table name index: %u"), @@ -297,15 +416,16 @@ Sized_dynobj::do_read_symbols(Read_symbols_data* sd) sd->symbol_names = this->get_lasting_view(strtabshdr.get_sh_offset(), strtabshdr.get_sh_size(), - true); - sd->symbol_names_size = strtabshdr.get_sh_size(); + false, false); + sd->symbol_names_size = + convert_to_section_size_type(strtabshdr.get_sh_size()); // Get the version information. unsigned int dummy; this->read_dynsym_section(pshdrs, versym_shndx, elfcpp::SHT_GNU_versym, - dynsym_shndx, &sd->versym, &sd->versym_size, - &dummy); + this->dynsym_shndx_, + &sd->versym, &sd->versym_size, &dummy); // We require that the version definition and need section link // to the same string table as the dynamic symbol table. This @@ -322,20 +442,33 @@ Sized_dynobj::do_read_symbols(Read_symbols_data* sd) } // Read the SHT_DYNAMIC section to find whether this shared object - // has a DT_SONAME tag. This doesn't really have anything to do - // with reading the symbols, but this is a convenient place to do - // it. + // has a DT_SONAME tag and to record any DT_NEEDED tags. This + // doesn't really have anything to do with reading the symbols, but + // this is a convenient place to do it. if (dynamic_shndx != -1U) - this->set_soname(pshdrs, dynamic_shndx, strtab_shndx, - (sd->symbol_names == NULL - ? NULL - : sd->symbol_names->data()), - sd->symbol_names_size); + this->read_dynamic(pshdrs, dynamic_shndx, strtab_shndx, + (sd->symbol_names == NULL + ? NULL + : sd->symbol_names->data()), + sd->symbol_names_size); +} + +// Return the Xindex structure to use for object with lots of +// sections. + +template +Xindex* +Sized_dynobj::do_initialize_xindex() +{ + gold_assert(this->dynsym_shndx_ != -1U); + Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset()); + xindex->initialize_symtab_xindex(this, this->dynsym_shndx_); + return 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 @@ -370,6 +503,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; @@ -407,10 +541,10 @@ Sized_dynobj::make_verdef_map( return; const char* names = reinterpret_cast(sd->symbol_names->data()); - off_t names_size = sd->symbol_names_size; + section_size_type names_size = sd->symbol_names_size; const unsigned char* pverdef = sd->verdef->data(); - off_t verdef_size = sd->verdef_size; + section_size_type verdef_size = sd->verdef_size; const unsigned int count = sd->verdef_info; const unsigned char* p = pverdef; @@ -425,7 +559,7 @@ Sized_dynobj::make_verdef_map( return; } - const unsigned int vd_ndx = verdef.get_vd_ndx(); + const section_size_type vd_ndx = verdef.get_vd_ndx(); // The GNU linker clears the VERSYM_HIDDEN bit. I'm not // sure why. @@ -433,36 +567,40 @@ Sized_dynobj::make_verdef_map( // The first Verdaux holds the name of this version. Subsequent // ones are versions that this one depends upon, which we don't // care about here. - const unsigned int vd_cnt = verdef.get_vd_cnt(); + const section_size_type vd_cnt = verdef.get_vd_cnt(); if (vd_cnt < 1) { - this->error(_("verdef vd_cnt field too small: %u"), vd_cnt); + this->error(_("verdef vd_cnt field too small: %u"), + static_cast(vd_cnt)); return; } - const unsigned int vd_aux = verdef.get_vd_aux(); + const section_size_type vd_aux = verdef.get_vd_aux(); if ((p - pverdef) + vd_aux >= verdef_size) { - this->error(_("verdef vd_aux field out of range: %u"), vd_aux); + this->error(_("verdef vd_aux field out of range: %u"), + static_cast(vd_aux)); return; } const unsigned char* pvda = p + vd_aux; elfcpp::Verdaux verdaux(pvda); - const unsigned int vda_name = verdaux.get_vda_name(); + const section_size_type vda_name = verdaux.get_vda_name(); if (vda_name >= names_size) { - this->error(_("verdaux vda_name field out of range: %u"), vda_name); + this->error(_("verdaux vda_name field out of range: %u"), + static_cast(vda_name)); return; } this->set_version_map(version_map, vd_ndx, names + vda_name); - const unsigned int vd_next = verdef.get_vd_next(); + const section_size_type vd_next = verdef.get_vd_next(); if ((p - pverdef) + vd_next >= verdef_size) { - this->error(_("verdef vd_next field out of range: %u"), vd_next); + this->error(_("verdef vd_next field out of range: %u"), + static_cast(vd_next)); return; } @@ -482,10 +620,10 @@ Sized_dynobj::make_verneed_map( return; const char* names = reinterpret_cast(sd->symbol_names->data()); - off_t names_size = sd->symbol_names_size; + section_size_type names_size = sd->symbol_names_size; const unsigned char* pverneed = sd->verneed->data(); - const off_t verneed_size = sd->verneed_size; + const section_size_type verneed_size = sd->verneed_size; const unsigned int count = sd->verneed_info; const unsigned char* p = pverneed; @@ -500,11 +638,12 @@ Sized_dynobj::make_verneed_map( return; } - const unsigned int vn_aux = verneed.get_vn_aux(); + const section_size_type vn_aux = verneed.get_vn_aux(); if ((p - pverneed) + vn_aux >= verneed_size) { - this->error(_("verneed vn_aux field out of range: %u"), vn_aux); + this->error(_("verneed vn_aux field out of range: %u"), + static_cast(vn_aux)); return; } @@ -518,28 +657,29 @@ Sized_dynobj::make_verneed_map( if (vna_name >= names_size) { this->error(_("vernaux vna_name field out of range: %u"), - vna_name); + static_cast(vna_name)); return; } this->set_version_map(version_map, vernaux.get_vna_other(), names + vna_name); - const unsigned int vna_next = vernaux.get_vna_next(); + const section_size_type vna_next = vernaux.get_vna_next(); if ((pvna - pverneed) + vna_next >= verneed_size) { this->error(_("verneed vna_next field out of range: %u"), - vna_next); + static_cast(vna_next)); return; } pvna += vna_next; } - const unsigned int vn_next = verneed.get_vn_next(); + const section_size_type vn_next = verneed.get_vn_next(); if ((p - pverneed) + vn_next >= verneed_size) { - this->error(_("verneed vn_next field out of range: %u"), vn_next); + this->error(_("verneed vn_next field out of range: %u"), + static_cast(vn_next)); return; } @@ -571,7 +711,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) { @@ -583,7 +724,8 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, const int sym_size = This::sym_size; const size_t symcount = sd->symbols_size / sym_size; - if (static_cast(symcount * sym_size) != sd->symbols_size) + gold_assert(sd->external_symbols_offset == 0); + if (symcount * sym_size != sd->symbols_size) { this->error(_("size of dynamic symbols is not multiple of symbol size")); return; @@ -592,6 +734,16 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, Version_map version_map; this->make_version_map(sd, &version_map); + // 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); + } + const char* sym_names = reinterpret_cast(sd->symbol_names->data()); symtab->add_from_dynobj(this, sd->symbols->data(), symcount, @@ -600,7 +752,9 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, ? NULL : sd->versym->data()), sd->versym_size, - &version_map); + &version_map, + this->symbols_, + &this->defined_count_); delete sd->symbols; sd->symbols = NULL; @@ -621,6 +775,79 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, delete sd->verneed; sd->verneed = NULL; } + + // This is normally the last time we will read any data from this + // file. + 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 +void +Sized_dynobj::do_get_global_symbol_counts( + const Symbol_table*, + size_t* defined, + size_t* used) const +{ + *defined = this->defined_count_; + size_t count = 0; + for (typename Symbols::const_iterator p = this->symbols_->begin(); + p != this->symbols_->end(); + ++p) + if (*p != NULL + && (*p)->source() == Symbol::FROM_OBJECT + && (*p)->object() == this + && (*p)->is_defined() + && (*p)->has_dynsym_index()) + ++count; + *used = count; } // Given a vector of hash codes, compute the number of hash buckets to @@ -636,20 +863,22 @@ Dynobj::compute_bucket_count(const std::vector& hashcodes, // based on the number of symbols there are. If there are fewer // than 3 symbols we use 1 bucket, fewer than 17 symbols we use 3 // buckets, fewer than 37 we use 17 buckets, and so forth. We never - // use more than 32771 buckets. This is straight from the old GNU + // use more than 262147 buckets. This is straight from the old GNU // linker. static const unsigned int buckets[] = { 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209, - 16411, 32771 + 16411, 32771, 65537, 131101, 262147 }; const int buckets_count = sizeof buckets / sizeof buckets[0]; unsigned int symcount = hashcodes.size(); unsigned int ret = 1; + const double full_fraction + = 1.0 - parameters->options().hash_bucket_empty_fraction(); for (int i = 0; i < buckets_count; ++i) { - if (symcount < buckets[i]) + if (symcount < buckets[i] * full_fraction) break; ret = buckets[i]; } @@ -717,31 +946,59 @@ Dynobj::create_elf_hash_table(const std::vector& dynsyms, bucket[bucketpos] = dynsym_index; } + int size = parameters->target().hash_entry_size(); unsigned int hashlen = ((2 + bucketcount + local_dynsym_count + dynsym_count) - * 4); + * size / 8); unsigned char* phash = new unsigned char[hashlen]; - if (parameters->is_big_endian()) + bool big_endian = parameters->target().is_big_endian(); + if (size == 32) { + if (big_endian) + { #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) - Dynobj::sized_create_elf_hash_table(bucket, chain, phash, - hashlen); + Dynobj::sized_create_elf_hash_table<32, true>(bucket, chain, phash, + hashlen); #else - gold_unreachable(); + gold_unreachable(); #endif + } + else + { +#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) + Dynobj::sized_create_elf_hash_table<32, false>(bucket, chain, phash, + hashlen); +#else + gold_unreachable(); +#endif + } } - else + else if (size == 64) { + if (big_endian) + { +#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) + Dynobj::sized_create_elf_hash_table<64, true>(bucket, chain, phash, + hashlen); +#else + gold_unreachable(); +#endif + } + else + { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) - Dynobj::sized_create_elf_hash_table(bucket, chain, phash, - hashlen); + Dynobj::sized_create_elf_hash_table<64, false>(bucket, chain, phash, + hashlen); #else - gold_unreachable(); + gold_unreachable(); #endif + } } + else + gold_unreachable(); *pphash = phash; *phashlen = hashlen; @@ -749,7 +1006,7 @@ Dynobj::create_elf_hash_table(const std::vector& dynsyms, // Fill in an ELF hash table. -template +template void Dynobj::sized_create_elf_hash_table(const std::vector& bucket, const std::vector& chain, @@ -761,21 +1018,21 @@ Dynobj::sized_create_elf_hash_table(const std::vector& bucket, const unsigned int bucketcount = bucket.size(); const unsigned int chaincount = chain.size(); - elfcpp::Swap<32, big_endian>::writeval(p, bucketcount); - p += 4; - elfcpp::Swap<32, big_endian>::writeval(p, chaincount); - p += 4; + elfcpp::Swap::writeval(p, bucketcount); + p += size / 8; + elfcpp::Swap::writeval(p, chaincount); + p += size / 8; for (unsigned int i = 0; i < bucketcount; ++i) { - elfcpp::Swap<32, big_endian>::writeval(p, bucket[i]); - p += 4; + elfcpp::Swap::writeval(p, bucket[i]); + p += size / 8; } for (unsigned int i = 0; i < chaincount; ++i) { - elfcpp::Swap<32, big_endian>::writeval(p, chain[i]); - p += 4; + elfcpp::Swap::writeval(p, chain[i]); + p += size / 8; } gold_assert(static_cast(p - phash) == hashlen); @@ -830,9 +1087,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 { @@ -853,8 +1111,8 @@ Dynobj::create_gnu_hash_table(const std::vector& dynsyms, // For the actual data generation we call out to a templatized // function. - int size = parameters->get_size(); - bool big_endian = parameters->is_big_endian(); + int size = parameters->target().get_size(); + bool big_endian = parameters->target().is_big_endian(); if (size == 32) { if (big_endian) @@ -1059,8 +1317,7 @@ Dynobj::sized_create_gnu_hash_table( template unsigned char* -Verdef::write(const Stringpool* dynpool, bool is_last, unsigned char* pb - ACCEPT_SIZE_ENDIAN) const +Verdef::write(const Stringpool* dynpool, bool is_last, unsigned char* pb) const { const int verdef_size = elfcpp::Elf_sizes::verdef_size; const int verdaux_size = elfcpp::Elf_sizes::verdaux_size; @@ -1068,7 +1325,8 @@ Verdef::write(const Stringpool* dynpool, bool is_last, unsigned char* pb 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())); @@ -1139,7 +1397,7 @@ Verneed::finalize(unsigned int index) template unsigned char* Verneed::write(const Stringpool* dynpool, bool is_last, - unsigned char* pb ACCEPT_SIZE_ENDIAN) const + unsigned char* pb) const { const int verneed_size = elfcpp::Elf_sizes::verneed_size; const int vernaux_size = elfcpp::Elf_sizes::vernaux_size; @@ -1177,6 +1435,37 @@ Verneed::write(const Stringpool* dynpool, bool is_last, // Versions methods. +Versions::Versions(const Version_script_info& version_script, + Stringpool* dynpool) + : defs_(), needs_(), version_table_(), + is_finalized_(false), version_script_(version_script), + needs_base_version_(true) +{ + 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; + const char* version = dynpool->add(versions[k].c_str(), + true, &version_key); + Verdef* const vd = new Verdef( + version, + this->version_script_.get_dependencies(version), + false, false, false, false); + this->defs_.push_back(vd); + Key key(version_key, 0); + this->version_table_.insert(std::make_pair(key, vd)); + } + } +} + Versions::~Versions() { for (Defs::iterator p = this->defs_.begin(); @@ -1190,32 +1479,69 @@ 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* +Versions::get_dynobj_for_sym(const Symbol_table* symtab, + const Symbol* sym) const +{ + if (sym->is_copied_from_dynobj()) + return symtab->get_copy_source(sym); + else + { + Object* object = sym->object(); + gold_assert(object->is_dynamic()); + return static_cast(object); + } +} + // Record version information for a symbol going into the dynamic // symbol table. void -Versions::record_version(const General_options* options, +Versions::record_version(const Symbol_table* symtab, Stringpool* dynpool, const Symbol* sym) { gold_assert(!this->is_finalized_); gold_assert(sym->version() != NULL); + // A symbol defined as "sym@" is bound to an unspecified base version. + if (sym->version()[0] == '\0') + return; + Stringpool::Key version_key; const char* version = dynpool->add(sym->version(), false, &version_key); - if (!sym->is_from_dynobj()) + if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj()) { - if (parameters->output_is_shared()) - this->add_def(options, sym, version, version_key); + this->add_def(dynpool, sym, version, version_key); } else { // This is a version reference. - - Object* object = sym->object(); - gold_assert(object->is_dynamic()); - Dynobj* dynobj = static_cast(object); - + Dynobj* dynobj = this->get_dynobj_for_sym(symtab, sym); this->add_need(dynpool, dynobj->soname(), version, version_key); } } @@ -1223,8 +1549,8 @@ Versions::record_version(const General_options* options, // We've found a symbol SYM defined in version VERSION. void -Versions::add_def(const General_options* options, const Symbol* sym, - const char* version, Stringpool::Key version_key) +Versions::add_def(Stringpool* dynpool, const Symbol* sym, const char* version, + Stringpool::Key version_key) { Key k(version_key, 0); Version_base* const vbnull = NULL; @@ -1238,33 +1564,24 @@ Versions::add_def(const General_options* options, const Symbol* sym, // We have now seen a symbol in this version, so it is not // 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 { // If we are creating a shared object, it is an error to // find a definition of a symbol with a version which is not // in the version script. - if (parameters->output_is_shared()) - { - gold_error(_("symbol %s has undefined version %s"), - sym->name(), version); - return; - } - - // If this is the first version we are defining, first define - // the base version. FIXME: Should use soname here when - // creating a shared object. - Verdef* vdbase = new Verdef(options->output_file_name(), true, false, - true); - this->defs_.push_back(vdbase); + if (parameters->options().shared()) + gold_error(_("symbol %s has undefined version %s"), + sym->demangled_name().c_str(), version); // When creating a regular executable, automatically define // a new version. - Verdef* vd = new Verdef(version, false, false, false); + if (this->needs_base_version_) + this->define_base_version(dynpool); + Verdef* vd = new Verdef(version, std::vector(), + false, false, false, false); this->defs_.push_back(vd); ins.first->second = vd; } @@ -1307,6 +1624,10 @@ Versions::add_need(Stringpool* dynpool, const char* filename, const char* name, if (vn == NULL) { + // Create base version definition lazily for shared library. + if (parameters->options().shared() && this->needs_base_version_) + this->define_base_version(dynpool); + // We have a new filename. vn = new Verneed(filename); this->needs_.push_back(vn); @@ -1319,8 +1640,8 @@ Versions::add_need(Stringpool* dynpool, const char* filename, const char* name, // each new version definition. unsigned int -Versions::finalize(const Target* target, Symbol_table* symtab, - unsigned int dynsym_index, std::vector* syms) +Versions::finalize(Symbol_table* symtab, unsigned int dynsym_index, + std::vector* syms) { gold_assert(!this->is_finalized_); @@ -1336,14 +1657,17 @@ Versions::finalize(const Target* target, Symbol_table* symtab, // Create a version symbol if necessary. if (!(*p)->is_symbol_created()) { - Symbol* vsym = symtab->define_as_constant(target, (*p)->name(), - (*p)->name(), 0, 0, + Symbol* vsym = symtab->define_as_constant((*p)->name(), + (*p)->name(), + Symbol_table::PREDEFINED, + 0, 0, elfcpp::STT_OBJECT, elfcpp::STB_GLOBAL, elfcpp::STV_DEFAULT, 0, - false); + 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. @@ -1375,24 +1699,21 @@ Versions::finalize(const Target* target, Symbol_table* symtab, // pointers. unsigned int -Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const +Versions::version_index(const Symbol_table* symtab, const Stringpool* dynpool, + const Symbol* sym) const { Stringpool::Key version_key; const char* version = dynpool->find(sym->version(), &version_key); gold_assert(version != NULL); Key k; - if (!sym->is_from_dynobj()) + if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj()) { - if (!parameters->output_is_shared()) - return elfcpp::VER_NDX_GLOBAL; k = Key(version_key, 0); } else { - Object* object = sym->object(); - gold_assert(object->is_dynamic()); - Dynobj* dynobj = static_cast(object); + Dynobj* dynobj = this->get_dynobj_for_sym(symtab, sym); Stringpool::Key filename_key; const char* filename = dynpool->find(dynobj->soname(), &filename_key); @@ -1412,12 +1733,12 @@ Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const template void -Versions::symbol_section_contents(const Stringpool* dynpool, +Versions::symbol_section_contents(const Symbol_table* symtab, + const Stringpool* dynpool, unsigned int local_symcount, const std::vector& syms, unsigned char** pp, - unsigned int* psize - ACCEPT_SIZE_ENDIAN) const + unsigned int* psize) const { gold_assert(this->is_finalized_); @@ -1435,11 +1756,25 @@ Versions::symbol_section_contents(const Stringpool* dynpool, unsigned int version_index; const char* version = (*p)->version(); if (version == NULL) - version_index = elfcpp::VER_NDX_GLOBAL; + { + if ((*p)->is_defined() && !(*p)->is_from_dynobj()) + version_index = elfcpp::VER_NDX_GLOBAL; + else + version_index = elfcpp::VER_NDX_LOCAL; + } + else if (version[0] == '\0') + version_index = elfcpp::VER_NDX_GLOBAL; else - version_index = this->version_index(dynpool, *p); + version_index = this->version_index(symtab, dynpool, *p); + // If the symbol was defined as foo@V1 instead of foo@@V1, add + // the hidden bit. + if ((*p)->version() != NULL + && (*p)->is_defined() + && !(*p)->is_default() + && !(*p)->from_dyn()) + version_index |= elfcpp::VERSYM_HIDDEN; elfcpp::Swap<16, big_endian>::writeval(pbuf + (*p)->dynsym_index() * 2, - version_index); + version_index); } *pp = pbuf; @@ -1453,8 +1788,7 @@ template void Versions::def_section_contents(const Stringpool* dynpool, unsigned char** pp, unsigned int* psize, - unsigned int* pentries - ACCEPT_SIZE_ENDIAN) const + unsigned int* pentries) const { gold_assert(this->is_finalized_); gold_assert(!this->defs_.empty()); @@ -1479,9 +1813,9 @@ Versions::def_section_contents(const Stringpool* dynpool, for (p = this->defs_.begin(), i = 0; p != this->defs_.end(); ++p, ++i) - pb = (*p)->write SELECT_SIZE_ENDIAN_NAME(size, big_endian)( - dynpool, i + 1 >= this->defs_.size(), pb - SELECT_SIZE_ENDIAN(size, big_endian)); + pb = (*p)->write(dynpool, + i + 1 >= this->defs_.size(), + pb); gold_assert(static_cast(pb - pbuf) == sz); @@ -1496,9 +1830,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 - ACCEPT_SIZE_ENDIAN) const + unsigned char** pp, unsigned int* psize, + unsigned int* pentries) const { gold_assert(this->is_finalized_); gold_assert(!this->needs_.empty()); @@ -1523,9 +1856,9 @@ Versions::need_section_contents(const Stringpool* dynpool, for (p = this->needs_.begin(), i = 0; p != this->needs_.end(); ++p, ++i) - pb = (*p)->write SELECT_SIZE_ENDIAN_NAME(size, big_endian)( - dynpool, i + 1 >= this->needs_.size(), pb - SELECT_SIZE_ENDIAN(size, big_endian)); + pb = (*p)->write(dynpool, + i + 1 >= this->needs_.size(), + pb); gold_assert(static_cast(pb - pbuf) == sz); @@ -1561,48 +1894,48 @@ class Sized_dynobj<64, true>; template void Versions::symbol_section_contents<32, false>( + const Symbol_table*, const Stringpool*, unsigned int, const std::vector&, unsigned char**, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(32, false)) const; + unsigned int*) const; #endif #ifdef HAVE_TARGET_32_BIG template void Versions::symbol_section_contents<32, true>( + const Symbol_table*, const Stringpool*, unsigned int, const std::vector&, unsigned char**, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(32, true)) const; + unsigned int*) const; #endif #ifdef HAVE_TARGET_64_LITTLE template void Versions::symbol_section_contents<64, false>( + const Symbol_table*, const Stringpool*, unsigned int, const std::vector&, unsigned char**, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(64, false)) const; + unsigned int*) const; #endif #ifdef HAVE_TARGET_64_BIG template void Versions::symbol_section_contents<64, true>( + const Symbol_table*, const Stringpool*, unsigned int, const std::vector&, unsigned char**, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(64, true)) const; + unsigned int*) const; #endif #ifdef HAVE_TARGET_32_LITTLE @@ -1612,8 +1945,7 @@ Versions::def_section_contents<32, false>( const Stringpool*, unsigned char**, unsigned int*, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(32, false)) const; + unsigned int*) const; #endif #ifdef HAVE_TARGET_32_BIG @@ -1623,8 +1955,7 @@ Versions::def_section_contents<32, true>( const Stringpool*, unsigned char**, unsigned int*, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(32, true)) const; + unsigned int*) const; #endif #ifdef HAVE_TARGET_64_LITTLE @@ -1634,8 +1965,7 @@ Versions::def_section_contents<64, false>( const Stringpool*, unsigned char**, unsigned int*, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(64, false)) const; + unsigned int*) const; #endif #ifdef HAVE_TARGET_64_BIG @@ -1645,8 +1975,7 @@ Versions::def_section_contents<64, true>( const Stringpool*, unsigned char**, unsigned int*, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(64, true)) const; + unsigned int*) const; #endif #ifdef HAVE_TARGET_32_LITTLE @@ -1656,8 +1985,7 @@ Versions::need_section_contents<32, false>( const Stringpool*, unsigned char**, unsigned int*, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(32, false)) const; + unsigned int*) const; #endif #ifdef HAVE_TARGET_32_BIG @@ -1667,8 +1995,7 @@ Versions::need_section_contents<32, true>( const Stringpool*, unsigned char**, unsigned int*, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(32, true)) const; + unsigned int*) const; #endif #ifdef HAVE_TARGET_64_LITTLE @@ -1678,8 +2005,7 @@ Versions::need_section_contents<64, false>( const Stringpool*, unsigned char**, unsigned int*, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(64, false)) const; + unsigned int*) const; #endif #ifdef HAVE_TARGET_64_BIG @@ -1689,8 +2015,7 @@ Versions::need_section_contents<64, true>( const Stringpool*, unsigned char**, unsigned int*, - unsigned int* - ACCEPT_SIZE_ENDIAN_EXPLICIT(64, true)) const; + unsigned int*) const; #endif } // End namespace gold.