diff options
-rw-r--r-- | elfcpp/elfcpp.h | 128 | ||||
-rw-r--r-- | gold/dynobj.cc | 841 | ||||
-rw-r--r-- | gold/dynobj.h | 319 | ||||
-rw-r--r-- | gold/i386.cc | 14 | ||||
-rw-r--r-- | gold/layout.cc | 179 | ||||
-rw-r--r-- | gold/layout.h | 22 | ||||
-rw-r--r-- | gold/output.h | 8 | ||||
-rw-r--r-- | gold/po/gold.pot | 59 | ||||
-rw-r--r-- | gold/reloc.cc | 2 | ||||
-rw-r--r-- | gold/resolve.cc | 65 | ||||
-rw-r--r-- | gold/symtab.cc | 186 | ||||
-rw-r--r-- | gold/symtab.h | 76 | ||||
-rw-r--r-- | gold/target.h | 8 |
13 files changed, 1560 insertions, 347 deletions
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h index ba85b3d..305487f 100644 --- a/elfcpp/elfcpp.h +++ b/elfcpp/elfcpp.h @@ -692,6 +692,11 @@ struct Elf_sizes static const int rela_size = sizeof(internal::Rela_data<size>); // Size of ELF dynamic entry. static const int dyn_size = sizeof(internal::Dyn_data<size>); + // Size of ELF version structures. + static const int verdef_size = sizeof(internal::Verdef_data); + static const int verdaux_size = sizeof(internal::Verdaux_data); + static const int verneed_size = sizeof(internal::Verneed_data); + static const int vernaux_size = sizeof(internal::Vernaux_data); }; // Accessor class for the ELF file header. @@ -1378,6 +1383,46 @@ class Verdef const internal::Verdef_data* p_; }; +template<int size, bool big_endian> +class Verdef_write +{ + public: + Verdef_write(unsigned char* p) + : p_(reinterpret_cast<internal::Verdef_data*>(p)) + { } + + void + set_vd_version(Elf_Half v) + { this->p_->vd_version = Convert<16, big_endian>::convert_host(v); } + + void + set_vd_flags(Elf_Half v) + { this->p_->vd_flags = Convert<16, big_endian>::convert_host(v); } + + void + set_vd_ndx(Elf_Half v) + { this->p_->vd_ndx = Convert<16, big_endian>::convert_host(v); } + + void + set_vd_cnt(Elf_Half v) + { this->p_->vd_cnt = Convert<16, big_endian>::convert_host(v); } + + void + set_vd_hash(Elf_Word v) + { this->p_->vd_hash = Convert<32, big_endian>::convert_host(v); } + + void + set_vd_aux(Elf_Word v) + { this->p_->vd_aux = Convert<32, big_endian>::convert_host(v); } + + void + set_vd_next(Elf_Word v) + { this->p_->vd_next = Convert<32, big_endian>::convert_host(v); } + + private: + internal::Verdef_data* p_; +}; + // Accessor classes for auxiliary entries in the ELF SHT_GNU_verdef // section. @@ -1407,6 +1452,26 @@ class Verdaux const internal::Verdaux_data* p_; }; +template<int size, bool big_endian> +class Verdaux_write +{ + public: + Verdaux_write(unsigned char* p) + : p_(reinterpret_cast<internal::Verdaux_data*>(p)) + { } + + void + set_vda_name(Elf_Word v) + { this->p_->vda_name = Convert<32, big_endian>::convert_host(v); } + + void + set_vda_next(Elf_Word v) + { this->p_->vda_next = Convert<32, big_endian>::convert_host(v); } + + private: + internal::Verdaux_data* p_; +}; + // Accessor classes for entries in the ELF SHT_GNU_verneed section. template<int size, bool big_endian> @@ -1447,6 +1512,38 @@ class Verneed const internal::Verneed_data* p_; }; +template<int size, bool big_endian> +class Verneed_write +{ + public: + Verneed_write(unsigned char* p) + : p_(reinterpret_cast<internal::Verneed_data*>(p)) + { } + + void + set_vn_version(Elf_Half v) + { this->p_->vn_version = Convert<16, big_endian>::convert_host(v); } + + void + set_vn_cnt(Elf_Half v) + { this->p_->vn_cnt = Convert<16, big_endian>::convert_host(v); } + + void + set_vn_file(Elf_Word v) + { this->p_->vn_file = Convert<32, big_endian>::convert_host(v); } + + void + set_vn_aux(Elf_Word v) + { this->p_->vn_aux = Convert<32, big_endian>::convert_host(v); } + + void + set_vn_next(Elf_Word v) + { this->p_->vn_next = Convert<32, big_endian>::convert_host(v); } + + private: + internal::Verneed_data* p_; +}; + // Accessor classes for auxiliary entries in the ELF SHT_GNU_verneed // section. @@ -1488,6 +1585,37 @@ class Vernaux const internal::Vernaux_data* p_; }; +template<int size, bool big_endian> +class Vernaux_write +{ + public: + Vernaux_write(unsigned char* p) + : p_(reinterpret_cast<internal::Vernaux_data*>(p)) + { } + + void + set_vna_hash(Elf_Word v) + { this->p_->vna_hash = Convert<32, big_endian>::convert_host(v); } + + void + set_vna_flags(Elf_Half v) + { this->p_->vna_flags = Convert<16, big_endian>::convert_host(v); } + + void + set_vna_other(Elf_Half v) + { this->p_->vna_other = Convert<16, big_endian>::convert_host(v); } + + void + set_vna_name(Elf_Word v) + { this->p_->vna_name = Convert<32, big_endian>::convert_host(v); } + + void + set_vna_next(Elf_Word v) + { this->p_->vna_next = Convert<32, big_endian>::convert_host(v); } + + private: + internal::Vernaux_data* p_; +}; } // End namespace elfcpp. diff --git a/gold/dynobj.cc b/gold/dynobj.cc index ac5a74b..9871bde 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -392,7 +392,8 @@ Sized_dynobj<size, big_endian>::set_version_map( unsigned int ndx, const char* name) const { - gold_assert(ndx < version_map->size()); + if (ndx >= version_map->size()) + version_map->resize(ndx + 1); if ((*version_map)[ndx] != NULL) { fprintf(stderr, _("%s: %s: duplicate definition for version %u\n"), @@ -402,207 +403,191 @@ Sized_dynobj<size, big_endian>::set_version_map( (*version_map)[ndx] = name; } -// Create a vector mapping version numbers to version strings. +// Add mappings for the version definitions to VERSION_MAP. template<int size, bool big_endian> void -Sized_dynobj<size, big_endian>::make_version_map( +Sized_dynobj<size, big_endian>::make_verdef_map( Read_symbols_data* sd, Version_map* version_map) const { - if (sd->verdef == NULL && sd->verneed == NULL) + if (sd->verdef == NULL) return; - // First find the largest version index. - unsigned int maxver = 0; + const char* names = reinterpret_cast<const char*>(sd->symbol_names->data()); + off_t names_size = sd->symbol_names_size; - if (sd->verdef != NULL) + const unsigned char* pverdef = sd->verdef->data(); + off_t verdef_size = sd->verdef_size; + const unsigned int count = sd->verdef_info; + + const unsigned char* p = pverdef; + for (unsigned int i = 0; i < count; ++i) { - const unsigned char* pverdef = sd->verdef->data(); - off_t verdef_size = sd->verdef_size; - const unsigned int count = sd->verdef_info; + elfcpp::Verdef<size, big_endian> verdef(p); - const unsigned char* p = pverdef; - for (unsigned int i = 0; i < count; ++i) + if (verdef.get_vd_version() != elfcpp::VER_DEF_CURRENT) { - elfcpp::Verdef<size, big_endian> verdef(p); - - const unsigned int vd_ndx = verdef.get_vd_ndx(); + fprintf(stderr, _("%s: %s: unexpected verdef version %u\n"), + program_name, this->name().c_str(), verdef.get_vd_version()); + gold_exit(false); + } - // The GNU linker clears the VERSYM_HIDDEN bit. I'm not - // sure why. + const unsigned int vd_ndx = verdef.get_vd_ndx(); - if (vd_ndx > maxver) - maxver = vd_ndx; + // The GNU linker clears the VERSYM_HIDDEN bit. I'm not + // sure why. - const unsigned int vd_next = verdef.get_vd_next(); - if ((p - pverdef) + vd_next >= verdef_size) - { - fprintf(stderr, - _("%s: %s: verdef vd_next field out of range: %u\n"), - program_name, this->name().c_str(), vd_next); - gold_exit(false); - } - - p += vd_next; + // 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(); + if (vd_cnt < 1) + { + fprintf(stderr, _("%s: %s: verdef vd_cnt field too small: %u\n"), + program_name, this->name().c_str(), vd_cnt); + gold_exit(false); } - } - if (sd->verneed != NULL) - { - const unsigned char* pverneed = sd->verneed->data(); - off_t verneed_size = sd->verneed_size; - const unsigned int count = sd->verneed_info; - - const unsigned char* p = pverneed; - for (unsigned int i = 0; i < count; ++i) + const unsigned int vd_aux = verdef.get_vd_aux(); + if ((p - pverdef) + vd_aux >= verdef_size) { - elfcpp::Verneed<size, big_endian> verneed(p); + fprintf(stderr, + _("%s: %s: verdef vd_aux field out of range: %u\n"), + program_name, this->name().c_str(), vd_aux); + gold_exit(false); + } - const unsigned int vn_aux = verneed.get_vn_aux(); - if ((p - pverneed) + vn_aux >= verneed_size) - { - fprintf(stderr, - _("%s: %s: verneed vn_aux field out of range: %u\n"), - program_name, this->name().c_str(), vn_aux); - gold_exit(false); - } + const unsigned char* pvda = p + vd_aux; + elfcpp::Verdaux<size, big_endian> verdaux(pvda); - const unsigned int vn_cnt = verneed.get_vn_cnt(); - const unsigned char* pvna = p + vn_aux; - for (unsigned int j = 0; j < vn_cnt; ++j) - { - elfcpp::Vernaux<size, big_endian> vernaux(pvna); - - const unsigned int vna_other = vernaux.get_vna_other(); - if (vna_other > maxver) - maxver = vna_other; - - const unsigned int vna_next = vernaux.get_vna_next(); - if ((pvna - pverneed) + vna_next >= verneed_size) - { - fprintf(stderr, - _("%s: %s: verneed vna_next field " - "out of range: %u\n"), - program_name, this->name().c_str(), vna_next); - gold_exit(false); - } - - pvna += vna_next; - } + const unsigned int vda_name = verdaux.get_vda_name(); + if (vda_name >= names_size) + { + fprintf(stderr, + _("%s: %s: verdaux vda_name field out of range: %u\n"), + program_name, this->name().c_str(), vda_name); + gold_exit(false); + } - const unsigned int vn_next = verneed.get_vn_next(); - if ((p - pverneed) + vn_next >= verneed_size) - { - fprintf(stderr, - _("%s: %s: verneed vn_next field out of range: %u\n"), - program_name, this->name().c_str(), vn_next); - gold_exit(false); - } + this->set_version_map(version_map, vd_ndx, names + vda_name); - p += vn_next; + const unsigned int vd_next = verdef.get_vd_next(); + if ((p - pverdef) + vd_next >= verdef_size) + { + fprintf(stderr, + _("%s: %s: verdef vd_next field out of range: %u\n"), + program_name, this->name().c_str(), vd_next); + gold_exit(false); } + + p += vd_next; } +} - // Now MAXVER is the largest version index we have seen. +// Add mappings for the required versions to VERSION_MAP. - version_map->resize(maxver + 1); +template<int size, bool big_endian> +void +Sized_dynobj<size, big_endian>::make_verneed_map( + Read_symbols_data* sd, + Version_map* version_map) const +{ + if (sd->verneed == NULL) + return; const char* names = reinterpret_cast<const char*>(sd->symbol_names->data()); off_t names_size = sd->symbol_names_size; - if (sd->verdef != NULL) + const unsigned char* pverneed = sd->verneed->data(); + const off_t verneed_size = sd->verneed_size; + const unsigned int count = sd->verneed_info; + + const unsigned char* p = pverneed; + for (unsigned int i = 0; i < count; ++i) { - const unsigned char* pverdef = sd->verdef->data(); - off_t verdef_size = sd->verdef_size; - const unsigned int count = sd->verdef_info; + elfcpp::Verneed<size, big_endian> verneed(p); - const unsigned char* p = pverdef; - for (unsigned int i = 0; i < count; ++i) + if (verneed.get_vn_version() != elfcpp::VER_NEED_CURRENT) { - elfcpp::Verdef<size, big_endian> verdef(p); + fprintf(stderr, _("%s: %s: unexpected verneed version %u\n"), + program_name, this->name().c_str(), + verneed.get_vn_version()); + gold_exit(false); + } - const unsigned int vd_cnt = verdef.get_vd_cnt(); - if (vd_cnt < 1) - { - fprintf(stderr, _("%s: %s: verdef vd_cnt field too small: %u\n"), - program_name, this->name().c_str(), vd_cnt); - gold_exit(false); - } + const unsigned int vn_aux = verneed.get_vn_aux(); - const unsigned int vd_aux = verdef.get_vd_aux(); - if ((p - pverdef) + vd_aux >= verdef_size) - { - fprintf(stderr, - _("%s: %s: verdef vd_aux field out of range: %u\n"), - program_name, this->name().c_str(), vd_aux); - gold_exit(false); - } + if ((p - pverneed) + vn_aux >= verneed_size) + { + fprintf(stderr, + _("%s: %s: verneed vn_aux field out of range: %u\n"), + program_name, this->name().c_str(), vn_aux); + gold_exit(false); + } - const unsigned char* pvda = p + vd_aux; - elfcpp::Verdaux<size, big_endian> verdaux(pvda); + const unsigned int vn_cnt = verneed.get_vn_cnt(); + const unsigned char* pvna = p + vn_aux; + for (unsigned int j = 0; j < vn_cnt; ++j) + { + elfcpp::Vernaux<size, big_endian> vernaux(pvna); - const unsigned int vda_name = verdaux.get_vda_name(); - if (vda_name >= names_size) + const unsigned int vna_name = vernaux.get_vna_name(); + if (vna_name >= names_size) { fprintf(stderr, - _("%s: %s: verdaux vda_name field out of range: %u\n"), - program_name, this->name().c_str(), vda_name); + _("%s: %s: vernaux vna_name field " + "out of range: %u\n"), + program_name, this->name().c_str(), vna_name); gold_exit(false); } - this->set_version_map(version_map, verdef.get_vd_ndx(), - names + vda_name); + this->set_version_map(version_map, vernaux.get_vna_other(), + names + vna_name); - const unsigned int vd_next = verdef.get_vd_next(); - if ((p - pverdef) + vd_next >= verdef_size) + const unsigned int vna_next = vernaux.get_vna_next(); + if ((pvna - pverneed) + vna_next >= verneed_size) { fprintf(stderr, - _("%s: %s: verdef vd_next field out of range: %u\n"), - program_name, this->name().c_str(), vd_next); + _("%s: %s: verneed vna_next field " + "out of range: %u\n"), + program_name, this->name().c_str(), vna_next); gold_exit(false); } - p += vd_next; + pvna += vna_next; + } + + const unsigned int vn_next = verneed.get_vn_next(); + if ((p - pverneed) + vn_next >= verneed_size) + { + fprintf(stderr, + _("%s: %s: verneed vn_next field out of range: %u\n"), + program_name, this->name().c_str(), vn_next); + gold_exit(false); } + + p += vn_next; } +} - if (sd->verneed != NULL) - { - const unsigned char* pverneed = sd->verneed->data(); - const unsigned int count = sd->verneed_info; +// Create a vector mapping version numbers to version strings. - const unsigned char* p = pverneed; - for (unsigned int i = 0; i < count; ++i) - { - elfcpp::Verneed<size, big_endian> verneed(p); +template<int size, bool big_endian> +void +Sized_dynobj<size, big_endian>::make_version_map( + Read_symbols_data* sd, + Version_map* version_map) const +{ + if (sd->verdef == NULL && sd->verneed == NULL) + return; - const unsigned int vn_aux = verneed.get_vn_aux(); - const unsigned int vn_cnt = verneed.get_vn_cnt(); - const unsigned char* pvna = p + vn_aux; - for (unsigned int j = 0; j < vn_cnt; ++j) - { - elfcpp::Vernaux<size, big_endian> vernaux(pvna); - - const unsigned int vna_name = vernaux.get_vna_name(); - if (vna_name >= names_size) - { - fprintf(stderr, - _("%s: %s: vernaux vna_name field " - "out of range: %u\n"), - program_name, this->name().c_str(), vna_name); - gold_exit(false); - } - - this->set_version_map(version_map, vernaux.get_vna_other(), - names + vna_name); - - pvna += vernaux.get_vna_next(); - } + // A guess at the maximum version number we will see. If this is + // wrong we will be less efficient but still correct. + version_map->reserve(sd->verdef_info + sd->verneed_info * 10); - p += verneed.get_vn_next(); - } - } + this->make_verdef_map(sd, version_map); + this->make_verneed_map(sd, version_map); } // Add the dynamic symbols to the symbol table. @@ -1059,6 +1044,478 @@ Dynobj::sized_create_gnu_hash_table( *pphash = phash; } +// Verdef methods. + +// Write this definition to a buffer for the output section. + +template<int size, bool big_endian> +unsigned char* +Verdef::write(const Stringpool* dynpool, bool is_last, unsigned char* pb) const +{ + const int verdef_size = elfcpp::Elf_sizes<size>::verdef_size; + const int verdaux_size = elfcpp::Elf_sizes<size>::verdaux_size; + + elfcpp::Verdef_write<size, big_endian> 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)); + vd.set_vd_ndx(this->index()); + vd.set_vd_cnt(1 + this->deps_.size()); + vd.set_vd_hash(Dynobj::elf_hash(this->name())); + vd.set_vd_aux(verdef_size); + vd.set_vd_next(is_last + ? 0 + : verdef_size + (1 + this->deps_.size()) * verdaux_size); + pb += verdef_size; + + elfcpp::Verdaux_write<size, big_endian> vda(pb); + vda.set_vda_name(dynpool->get_offset(this->name())); + vda.set_vda_next(this->deps_.empty() ? 0 : verdaux_size); + pb += verdaux_size; + + Deps::const_iterator p; + unsigned int i; + for (p = this->deps_.begin(), i = 0; + p != this->deps_.end(); + ++p, ++i) + { + elfcpp::Verdaux_write<size, big_endian> vda(pb); + vda.set_vda_name(dynpool->get_offset(*p)); + vda.set_vda_next(i + 1 >= this->deps_.size() ? 0 : verdaux_size); + pb += verdaux_size; + } + + return pb; +} + +// Verneed methods. + +Verneed::~Verneed() +{ + for (Need_versions::iterator p = this->need_versions_.begin(); + p != this->need_versions_.end(); + ++p) + delete *p; +} + +// Add a new version to this file reference. + +Verneed_version* +Verneed::add_name(const char* name) +{ + Verneed_version* vv = new Verneed_version(name); + this->need_versions_.push_back(vv); + return vv; +} + +// Set the version indexes starting at INDEX. + +unsigned int +Verneed::finalize(unsigned int index) +{ + for (Need_versions::iterator p = this->need_versions_.begin(); + p != this->need_versions_.end(); + ++p) + { + (*p)->set_index(index); + ++index; + } + return index; +} + +// Write this list of referenced versions to a buffer for the output +// section. + +template<int size, bool big_endian> +unsigned char* +Verneed::write(const Stringpool* dynpool, bool is_last, + unsigned char* pb) const +{ + const int verneed_size = elfcpp::Elf_sizes<size>::verneed_size; + const int vernaux_size = elfcpp::Elf_sizes<size>::vernaux_size; + + elfcpp::Verneed_write<size, big_endian> vn(pb); + vn.set_vn_version(elfcpp::VER_NEED_CURRENT); + vn.set_vn_cnt(this->need_versions_.size()); + vn.set_vn_file(dynpool->get_offset(this->filename())); + vn.set_vn_aux(verneed_size); + vn.set_vn_next(is_last + ? 0 + : verneed_size + this->need_versions_.size() * vernaux_size); + pb += verneed_size; + + Need_versions::const_iterator p; + unsigned int i; + for (p = this->need_versions_.begin(), i = 0; + p != this->need_versions_.end(); + ++p, ++i) + { + elfcpp::Vernaux_write<size, big_endian> vna(pb); + vna.set_vna_hash(Dynobj::elf_hash((*p)->version())); + // FIXME: We need to sometimes set VER_FLG_WEAK here. + vna.set_vna_flags(0); + vna.set_vna_other((*p)->index()); + vna.set_vna_name(dynpool->get_offset((*p)->version())); + vna.set_vna_next(i + 1 >= this->need_versions_.size() + ? 0 + : vernaux_size); + pb += vernaux_size; + } + + return pb; +} + +// Versions methods. + +Versions::~Versions() +{ + for (Defs::iterator p = this->defs_.begin(); + p != this->defs_.end(); + ++p) + delete *p; + + for (Needs::iterator p = this->needs_.begin(); + p != this->needs_.end(); + ++p) + delete *p; +} + +// Record version information for a symbol going into the dynamic +// symbol table. + +void +Versions::record_version(const General_options* options, + Stringpool* dynpool, const Symbol* sym) +{ + gold_assert(!this->is_finalized_); + gold_assert(sym->version() != NULL); + + Stringpool::Key version_key; + const char* version = dynpool->add(sym->version(), &version_key); + + if (!sym->is_from_dynobj()) + this->add_def(options, sym, version, version_key); + else + { + // This is a version reference. + + Object* object = sym->object(); + gold_assert(object->is_dynamic()); + Dynobj* dynobj = static_cast<Dynobj*>(object); + + this->add_need(dynpool, dynobj->soname(), version, version_key); + } +} + +// 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) +{ + Key k(version_key, 0); + Version_base* const vbnull = NULL; + std::pair<Version_table::iterator, bool> ins = + this->version_table_.insert(std::make_pair(k, vbnull)); + + if (!ins.second) + { + // We already have an entry for this version. + Version_base* vb = ins.first->second; + + // We have now seen a symbol in this version, so it is not + // weak. + 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 (options->is_shared()) + { + fprintf(stderr, _("%s: symbol %s has undefined version %s\n"), + program_name, sym->name(), version); + gold_exit(false); + } + + // 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); + + // When creating a regular executable, automatically define + // a new version. + Verdef* vd = new Verdef(version, false, false, false); + this->defs_.push_back(vd); + ins.first->second = vd; + } +} + +// Add a reference to version NAME in file FILENAME. + +void +Versions::add_need(Stringpool* dynpool, const char* filename, const char* name, + Stringpool::Key name_key) +{ + Stringpool::Key filename_key; + filename = dynpool->add(filename, &filename_key); + + Key k(name_key, filename_key); + Version_base* const vbnull = NULL; + std::pair<Version_table::iterator, bool> ins = + this->version_table_.insert(std::make_pair(k, vbnull)); + + if (!ins.second) + { + // We already have an entry for this filename/version. + return; + } + + // See whether we already have this filename. We don't expect many + // version references, so we just do a linear search. This could be + // replaced by a hash table. + Verneed* vn = NULL; + for (Needs::iterator p = this->needs_.begin(); + p != this->needs_.end(); + ++p) + { + if ((*p)->filename() == filename) + { + vn = *p; + break; + } + } + + if (vn == NULL) + { + // We have a new filename. + vn = new Verneed(filename); + this->needs_.push_back(vn); + } + + ins.first->second = vn->add_name(name); +} + +// Set the version indexes. Create a new dynamic version symbol for +// each new version definition. + +unsigned int +Versions::finalize(const Target* target, Symbol_table* symtab, + unsigned int dynsym_index, std::vector<Symbol*>* syms) +{ + gold_assert(!this->is_finalized_); + + unsigned int vi = 1; + + for (Defs::iterator p = this->defs_.begin(); + p != this->defs_.end(); + ++p) + { + (*p)->set_index(vi); + ++vi; + + // Create a version symbol if necessary. + if (!(*p)->is_symbol_created()) + { + Symbol* vsym =symtab->define_as_constant(target, (*p)->name(), + (*p)->name(), 0, 0, + elfcpp::STT_OBJECT, + elfcpp::STB_GLOBAL, + elfcpp::STV_DEFAULT, 0, + false); + vsym->set_needs_dynsym_entry(); + ++dynsym_index; + syms->push_back(vsym); + // The name is already in the dynamic pool. + } + } + + // Index 1 is used for global symbols. + if (vi == 1) + { + gold_assert(this->defs_.empty()); + vi = 2; + } + + for (Needs::iterator p = this->needs_.begin(); + p != this->needs_.end(); + ++p) + vi = (*p)->finalize(vi); + + this->is_finalized_ = true; + + return dynsym_index; +} + +// Return the version index to use for a symbol. This does two hash +// table lookups: one in DYNPOOL and one in this->version_table_. +// Another approach alternative would be store a pointer in SYM, which +// would increase the size of the symbol table. Or perhaps we could +// use a hash table from dynamic symbol pointer values to Version_base +// pointers. + +unsigned int +Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const +{ + Stringpool::Key version_key; + const char* version = dynpool->find(sym->version(), &version_key); + gold_assert(version != NULL); + + Version_table::const_iterator p; + if (!sym->is_from_dynobj()) + { + Key k(version_key, 0); + p = this->version_table_.find(k); + } + else + { + Object* object = sym->object(); + gold_assert(object->is_dynamic()); + Dynobj* dynobj = static_cast<Dynobj*>(object); + + Stringpool::Key filename_key; + const char* filename = dynpool->find(dynobj->soname(), &filename_key); + gold_assert(filename != NULL); + + Key k(version_key, filename_key); + p = this->version_table_.find(k); + } + + gold_assert(p != this->version_table_.end()); + + return p->second->index(); +} + +// Return an allocated buffer holding the contents of the symbol +// version section. + +template<int size, bool big_endian> +void +Versions::symbol_section_contents(const Stringpool* dynpool, + unsigned int local_symcount, + const std::vector<Symbol*>& syms, + unsigned char** pp, + unsigned int* psize) const +{ + gold_assert(this->is_finalized_); + + unsigned int sz = (local_symcount + syms.size()) * 2; + unsigned char* pbuf = new unsigned char[sz]; + + for (unsigned int i = 0; i < local_symcount; ++i) + elfcpp::Swap<16, big_endian>::writeval(pbuf + i * 2, + elfcpp::VER_NDX_LOCAL); + + for (std::vector<Symbol*>::const_iterator p = syms.begin(); + p != syms.end(); + ++p) + { + unsigned int version_index; + const char* version = (*p)->version(); + if (version == NULL) + version_index = elfcpp::VER_NDX_GLOBAL; + else + version_index = this->version_index(dynpool, *p); + elfcpp::Swap<16, big_endian>::writeval(pbuf + (*p)->dynsym_index() * 2, + version_index); + } + + *pp = pbuf; + *psize = sz; +} + +// Return an allocated buffer holding the contents of the version +// definition section. + +template<int size, bool big_endian> +void +Versions::def_section_contents(const Stringpool* dynpool, + unsigned char** pp, unsigned int* psize, + unsigned int* pentries) const +{ + gold_assert(this->is_finalized_); + gold_assert(!this->defs_.empty()); + + const int verdef_size = elfcpp::Elf_sizes<size>::verdef_size; + const int verdaux_size = elfcpp::Elf_sizes<size>::verdaux_size; + + unsigned int sz = 0; + for (Defs::const_iterator p = this->defs_.begin(); + p != this->defs_.end(); + ++p) + { + sz += verdef_size + verdaux_size; + sz += (*p)->count_dependencies() * verdaux_size; + } + + unsigned char* pbuf = new unsigned char[sz]; + + unsigned char* pb = pbuf; + Defs::const_iterator p; + unsigned int i; + for (p = this->defs_.begin(), i = 0; + p != this->defs_.end(); + ++p, ++i) + pb = (*p)->write<size, big_endian>(dynpool, + i + 1 >= this->defs_.size(), + pb); + + gold_assert(static_cast<unsigned int>(pb - pbuf) == sz); + + *pp = pbuf; + *psize = sz; + *pentries = this->defs_.size(); +} + +// Return an allocated buffer holding the contents of the version +// reference section. + +template<int size, bool big_endian> +void +Versions::need_section_contents(const Stringpool* dynpool, + unsigned char** pp, unsigned int *psize, + unsigned int *pentries) const +{ + gold_assert(this->is_finalized_); + gold_assert(!this->needs_.empty()); + + const int verneed_size = elfcpp::Elf_sizes<size>::verneed_size; + const int vernaux_size = elfcpp::Elf_sizes<size>::vernaux_size; + + unsigned int sz = 0; + for (Needs::const_iterator p = this->needs_.begin(); + p != this->needs_.end(); + ++p) + { + sz += verneed_size; + sz += (*p)->count_versions() * vernaux_size; + } + + unsigned char* pbuf = new unsigned char[sz]; + + unsigned char* pb = pbuf; + Needs::const_iterator p; + unsigned int i; + for (p = this->needs_.begin(), i = 0; + p != this->needs_.end(); + ++p, ++i) + pb = (*p)->write<size, big_endian>(dynpool, + i + 1 >= this->needs_.size(), + pb); + + gold_assert(static_cast<unsigned int>(pb - pbuf) == sz); + + *pp = pbuf; + *psize = sz; + *pentries = this->needs_.size(); +} + // Instantiate the templates we need. We could use the configure // script to restrict this to only the ones for implemented targets. @@ -1074,4 +1531,92 @@ class Sized_dynobj<64, false>; template class Sized_dynobj<64, true>; +template +void +Versions::symbol_section_contents<32, false>(const Stringpool*, + unsigned int, + const std::vector<Symbol*>&, + unsigned char**, + unsigned int*) const; + +template +void +Versions::symbol_section_contents<32, true>(const Stringpool*, + unsigned int, + const std::vector<Symbol*>&, + unsigned char**, + unsigned int*) const; + +template +void +Versions::symbol_section_contents<64, false>(const Stringpool*, + unsigned int, + const std::vector<Symbol*>&, + unsigned char**, + unsigned int*) const; + +template +void +Versions::symbol_section_contents<64, true>(const Stringpool*, + unsigned int, + const std::vector<Symbol*>&, + unsigned char**, + unsigned int*) const; + +template +void +Versions::def_section_contents<32, false>(const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; + +template +void +Versions::def_section_contents<32, true>(const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; + +template +void +Versions::def_section_contents<64, false>(const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; + +template +void +Versions::def_section_contents<64, true>(const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; + +template +void +Versions::need_section_contents<32, false>(const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; + +template +void +Versions::need_section_contents<32, true>(const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; + +template +void +Versions::need_section_contents<64, false>(const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; + +template +void +Versions::need_section_contents<64, true>(const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; + } // End namespace gold. diff --git a/gold/dynobj.h b/gold/dynobj.h index bc877c4..9e5dd43 100644 --- a/gold/dynobj.h +++ b/gold/dynobj.h @@ -5,11 +5,15 @@ #include <vector> +#include "stringpool.h" #include "object.h" namespace gold { +class General_options; +class Stringpool; + // A dynamic object (ET_DYN). This is an abstract base class itself. // The implementations is the template class Sized_dynobj. @@ -24,6 +28,10 @@ class Dynobj : public Object const char* soname() const; + // Compute the ELF hash code for a string. + static uint32_t + elf_hash(const char*); + // Create a standard ELF hash table, setting *PPHASH and *PHASHLEN. // DYNSYMS is the global dynamic symbols. LOCAL_DYNSYM_COUNT is the // number of local dynamic symbols, which is the index of the first @@ -50,10 +58,6 @@ class Dynobj : public Object { this->soname_.assign(s); } private: - // Compute the ELF hash code for a string. - static uint32_t - elf_hash(const char*); - // Compute the GNU hash code for a string. static uint32_t gnu_hash(const char*); @@ -166,6 +170,14 @@ class Sized_dynobj : public Dynobj void make_version_map(Read_symbols_data* sd, Version_map*) const; + // Add version definitions to the version map. + void + make_verdef_map(Read_symbols_data* sd, Version_map*) const; + + // Add version references to the version map. + void + make_verneed_map(Read_symbols_data* sd, Version_map*) const; + // Add an entry to the version map. void set_version_map(Version_map*, unsigned int ndx, const char* name) const; @@ -174,6 +186,305 @@ class Sized_dynobj : public Dynobj elfcpp::Elf_file<size, big_endian, Object> elf_file_; }; +// A base class for Verdef and Verneed_version which just handles the +// version index which will be stored in the SHT_GNU_versym section. + +class Version_base +{ + public: + Version_base() + : index_(-1U) + { } + + virtual + ~Version_base() + { } + + // Return the version index. + unsigned int + index() const + { + gold_assert(this->index_ != -1U); + return this->index_; + } + + // Set the version index. + void + set_index(unsigned int index) + { + gold_assert(this->index_ == -1U); + this->index_ = index; + } + + // Clear the weak flag in a version definition. + virtual void + clear_weak() = 0; + + private: + Version_base(const Version_base&); + Version_base& operator=(const Version_base&); + + // The index of the version definition or reference. + unsigned int index_; +}; + +// This class handles a version being defined in the file we are +// generating. + +class Verdef : public Version_base +{ + public: + Verdef(const char* name, bool is_base, bool is_weak, bool is_symbol_created) + : name_(name), deps_(), is_base_(is_base), is_weak_(is_weak), + is_symbol_created_(is_symbol_created) + { } + + // Return the version name. + const char* + name() const + { return this->name_; } + + // Return the number of dependencies. + unsigned int + count_dependencies() const + { return this->deps_.size(); } + + // Add a dependency to this version. The NAME should be + // canonicalized in the dynamic Stringpool. + void + add_dependency(const char* name) + { this->deps_.push_back(name); } + + // Return whether this definition is weak. + bool + is_weak() const + { return this->is_weak_; } + + // Clear the weak flag. + void + clear_weak() + { this->is_weak_ = false; } + + // Return whether a version symbol has been created for this + // definition. + bool + is_symbol_created() const + { return this->is_symbol_created_; } + + // Write contents to buffer. + template<int size, bool big_endian> + unsigned char* + write(const Stringpool*, bool is_last, unsigned char*) const; + + private: + Verdef(const Verdef&); + Verdef& operator=(const Verdef&); + + // The type of the list of version dependencies. Each dependency + // should be canonicalized in the dynamic Stringpool. + typedef std::vector<const char*> Deps; + + // The name of this version. This should be canonicalized in the + // dynamic Stringpool. + const char* name_; + // A list of other versions which this version depends upon. + Deps deps_; + // Whether this is the base version. + bool is_base_; + // Whether this version is weak. + bool is_weak_; + // Whether a version symbol has been created. + bool is_symbol_created_; +}; + +// A referened version. This will be associated with a filename by +// Verneed. + +class Verneed_version : public Version_base +{ + public: + Verneed_version(const char* version) + : version_(version) + { } + + // Return the version name. + const char* + version() const + { return this->version_; } + + // Clear the weak flag. This is invalid for a reference. + void + clear_weak() + { gold_unreachable(); } + + private: + Verneed_version(const Verneed_version&); + Verneed_version& operator=(const Verneed_version&); + + const char* version_; +}; + +// Version references in a single dynamic object. + +class Verneed +{ + public: + Verneed(const char* filename) + : filename_(filename), need_versions_() + { } + + ~Verneed(); + + // Return the file name. + const char* + filename() const + { return this->filename_; } + + // Return the number of versions. + unsigned int + count_versions() const + { return this->need_versions_.size(); } + + // Add a version name. The name should be canonicalized in the + // dynamic Stringpool. If the name is already present, this does + // nothing. + Verneed_version* + add_name(const char* name); + + // Set the version indexes, starting at INDEX. Return the updated + // INDEX. + unsigned int + finalize(unsigned int index); + + // Write contents to buffer. + template<int size, bool big_endian> + unsigned char* + write(const Stringpool*, bool is_last, unsigned char*) const; + + private: + Verneed(const Verneed&); + Verneed& operator=(const Verneed&); + + // The type of the list of version names. Each name should be + // canonicalized in the dynamic Stringpool. + typedef std::vector<Verneed_version*> Need_versions; + + // The filename of the dynamic object. This should be + // canonicalized in the dynamic Stringpool. + const char* filename_; + // The list of version names. + Need_versions need_versions_; +}; + +// This class handles version definitions and references which go into +// the output file. + +class Versions +{ + public: + Versions() + : defs_(), needs_(), version_table_(), is_finalized_(false) + { } + + ~Versions(); + + // SYM is going into the dynamic symbol table and has a version. + // Record the appropriate version information. + void + record_version(const General_options*, Stringpool*, const Symbol* sym); + + // Set the version indexes. DYNSYM_INDEX is the index we should use + // for the next dynamic symbol. We add new dynamic symbols to SYMS + // and return an updated DYNSYM_INDEX. + unsigned int + finalize(const Target*, Symbol_table* symtab, unsigned int dynsym_index, + std::vector<Symbol*>* syms); + + // Return whether there are any version definitions. + bool + any_defs() const + { return !this->defs_.empty(); } + + // Return whether there are any version references. + bool + any_needs() const + { return !this->needs_.empty(); } + + // Build an allocated buffer holding the contents of the symbol + // version section (.gnu.version). + template<int size, bool big_endian> + void + symbol_section_contents(const Stringpool*, unsigned int local_symcount, + const std::vector<Symbol*>& syms, + unsigned char**, unsigned int*) const; + + // Build an allocated buffer holding the contents of the version + // definition section (.gnu.version_d). + template<int size, bool big_endian> + void + def_section_contents(const Stringpool*, unsigned char**, + unsigned int* psize, unsigned int* pentries) const; + + // Build an allocated buffer holding the contents of the version + // reference section (.gnu.version_r). + template<int size, bool big_endian> + void + need_section_contents(const Stringpool*, unsigned char**, + unsigned int* psize, unsigned int* pentries) const; + + private: + // The type of the list of version definitions. + typedef std::vector<Verdef*> Defs; + + // The type of the list of version references. + typedef std::vector<Verneed*> Needs; + + // Handle a symbol SYM defined with version VERSION. + void + add_def(const General_options*, const Symbol* sym, const char* version, + Stringpool::Key); + + // Add a reference to version NAME in file FILENAME. + void + add_need(Stringpool*, const char* filename, const char* name, + Stringpool::Key); + + // Return the version index to use for SYM. + unsigned int + version_index(const Stringpool*, const Symbol* sym) const; + + // We keep a hash table mapping canonicalized name/version pairs to + // a version base. + typedef std::pair<Stringpool::Key, Stringpool::Key> Key; + + struct Version_table_hash + { + size_t + operator()(const Key& k) const + { return k.first + k.second; } + }; + + struct Version_table_eq + { + bool + operator()(const Key& k1, const Key& k2) const + { return k1.first == k2.first && k1.second == k2.second; } + }; + + typedef Unordered_map<Key, Version_base*, Version_table_hash, + Version_table_eq> Version_table; + + // The version definitions. + Defs defs_; + // The version references. + Needs needs_; + // The mapping from a canonicalized version/filename pair to a + // version index. The filename may be NULL. + Version_table version_table_; + // Whether the version indexes have been set. + bool is_finalized_; +}; + } // End namespace gold. #endif // !defined(GOLD_DYNOBJ_H) diff --git a/gold/i386.cc b/gold/i386.cc index ee3654c..dbbd2c0 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -247,7 +247,7 @@ Target_i386::got_section(const General_options* options, Symbol_table* symtab, this->got_plt_->set_space_size(3 * 4); // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT. - symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", + symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL, this->got_plt_, 0, 0, elfcpp::STT_OBJECT, elfcpp::STB_LOCAL, @@ -607,10 +607,10 @@ Target_i386::copy_reloc(const General_options* options, dynbss->set_space_size(dynbss_size + symsize); // Define the symbol in the .dynbss section. - symtab->define_in_output_data(this, ssym->name(), dynbss, offset, - symsize, ssym->type(), ssym->binding(), - ssym->visibility(), ssym->nonvis(), - false, false); + symtab->define_in_output_data(this, ssym->name(), ssym->version(), + dynbss, offset, symsize, ssym->type(), + ssym->binding(), ssym->visibility(), + ssym->nonvis(), false, false); // Add the COPY reloc. ssym->set_needs_dynsym_entry(); @@ -819,7 +819,7 @@ Target_i386::Scan::global(const General_options& options, // relocation in order to avoid a COPY relocation. gold_assert(!options.is_shared()); - if (gsym->is_defined_in_dynobj()) + if (gsym->is_from_dynobj()) { // This symbol is defined in a dynamic object. If it is a // function, we make a PLT entry. Otherwise we need to @@ -1050,7 +1050,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, } // Pick the value to use for symbols defined in shared objects. - if (gsym != NULL && gsym->is_defined_in_dynobj()) + if (gsym != NULL && gsym->is_from_dynobj()) { if (gsym->has_plt_offset()) value = target->plt_section()->address() + gsym->plt_offset(); diff --git a/gold/layout.cc b/gold/layout.cc index f424bb4..2d7a3fa 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -42,8 +42,8 @@ Layout::Layout(const General_options& options) : options_(options), namepool_(), sympool_(), dynpool_(), signatures_(), section_name_map_(), segment_list_(), section_list_(), unattached_section_list_(), special_output_list_(), - tls_segment_(NULL), symtab_section_(NULL), dynsym_section_(NULL), - dynamic_section_(NULL), dynamic_data_(NULL) + tls_segment_(NULL), symtab_section_(NULL), + dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL) { // Make space for more than enough segments for a typical file. // This is just for efficiency--it's OK if we wind up needing more. @@ -322,7 +322,7 @@ Layout::create_initial_dynamic_sections(const Input_objects* input_objects, (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE)); - symtab->define_in_output_data(input_objects->target(), "_DYNAMIC", + symtab->define_in_output_data(input_objects->target(), "_DYNAMIC", NULL, this->dynamic_section_, 0, 0, elfcpp::STT_OBJECT, elfcpp::STB_LOCAL, elfcpp::STV_HIDDEN, 0, false, false); @@ -405,9 +405,14 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R); this->segment_list_.push_back(phdr_seg); - // Create the dynamic symbol table, including the hash table, - // the dynamic relocations, and the version sections. - this->create_dynamic_symtab(target, symtab); + // Create the dynamic symbol table, including the hash table. + Output_section* dynstr; + std::vector<Symbol*> dynamic_symbols; + unsigned int local_dynamic_count; + Versions versions; + this->create_dynamic_symtab(target, symtab, &dynstr, + &local_dynamic_count, &dynamic_symbols, + &versions); // Create the .interp section to hold the name of the // interpreter, and put it in a PT_INTERP segment. @@ -416,6 +421,15 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) // Finish the .dynamic section to hold the dynamic data, and put // it in a PT_DYNAMIC segment. this->finish_dynamic_section(input_objects, symtab); + + // We should have added everything we need to the dynamic string + // table. + this->dynpool_.set_string_offsets(); + + // Create the version sections. We can't do this until the + // dynamic string table is complete. + this->create_version_sections(target, &versions, local_dynamic_count, + dynamic_symbols, dynstr); } // FIXME: Handle PT_GNU_STACK. @@ -831,7 +845,11 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff) // Create the dynamic symbol table. void -Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab) +Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, + Output_section **pdynstr, + unsigned int* plocal_dynamic_count, + std::vector<Symbol*>* pdynamic_symbols, + Versions* pversions) { // Count all the symbols in the dynamic symbol table, and set the // dynamic symbol indexes. @@ -859,13 +877,13 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab) // this->dynpool_. unsigned int local_symcount = index; - - std::vector<Symbol*> dynamic_symbols; + *plocal_dynamic_count = local_symcount; // FIXME: We have to tell set_dynsym_indexes whether the // -E/--export-dynamic option was used. - index = symtab->set_dynsym_indexes(index, &dynamic_symbols, - &this->dynpool_); + index = symtab->set_dynsym_indexes(&this->options_, target, index, + pdynamic_symbols, &this->dynpool_, + pversions); int symsize; unsigned int align; @@ -883,6 +901,8 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab) else gold_unreachable(); + // Create the dynamic symbol table section. + const char* dynsym_name = this->namepool_.add(".dynsym", NULL); Output_section* dynsym = this->make_output_section(dynsym_name, elfcpp::SHT_DYNSYM, @@ -902,6 +922,8 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab) odyn->add_section_address(elfcpp::DT_SYMTAB, dynsym); odyn->add_constant(elfcpp::DT_SYMENT, symsize); + // Create the dynamic string table section. + const char* dynstr_name = this->namepool_.add(".dynstr", NULL); Output_section* dynstr = this->make_output_section(dynstr_name, elfcpp::SHT_STRTAB, @@ -916,11 +938,15 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab) odyn->add_section_address(elfcpp::DT_STRTAB, dynstr); odyn->add_section_size(elfcpp::DT_STRSZ, dynstr); + *pdynstr = dynstr; + + // Create the hash tables. + // FIXME: We need an option to create a GNU hash table. unsigned char* phash; unsigned int hashlen; - Dynobj::create_elf_hash_table(target, dynamic_symbols, local_symcount, + Dynobj::create_elf_hash_table(target, *pdynamic_symbols, local_symcount, &phash, &hashlen); const char* hash_name = this->namepool_.add(".hash", NULL); @@ -939,6 +965,131 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab) odyn->add_section_address(elfcpp::DT_HASH, hashsec); } +// Create the version sections. + +void +Layout::create_version_sections(const Target* target, const Versions* versions, + unsigned int local_symcount, + const std::vector<Symbol*>& dynamic_symbols, + const Output_section* dynstr) +{ + if (!versions->any_defs() && !versions->any_needs()) + return; + + if (target->get_size() == 32) + { + if (target->is_big_endian()) + this->sized_create_version_sections<32, true>(versions, + local_symcount, + dynamic_symbols, + dynstr); + else + this->sized_create_version_sections<32, false>(versions, + local_symcount, + dynamic_symbols, + dynstr); + } + else if (target->get_size() == 64) + { + if (target->is_big_endian()) + this->sized_create_version_sections<64, true>(versions, + local_symcount, + dynamic_symbols, + dynstr); + else + this->sized_create_version_sections<64, false>(versions, + local_symcount, + dynamic_symbols, + dynstr); + } + else + gold_unreachable(); +} + +// Create the version sections, sized version. + +template<int size, bool big_endian> +void +Layout::sized_create_version_sections( + const Versions* versions, + unsigned int local_symcount, + const std::vector<Symbol*>& dynamic_symbols, + const Output_section* dynstr) +{ + const char* vname = this->namepool_.add(".gnu.version", NULL); + Output_section* vsec = this->make_output_section(vname, + elfcpp::SHT_GNU_versym, + elfcpp::SHF_ALLOC); + + unsigned char* vbuf; + unsigned int vsize; + versions->symbol_section_contents<size, big_endian>(&this->dynpool_, + local_symcount, + dynamic_symbols, + &vbuf, &vsize); + + Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2); + + vsec->add_output_section_data(vdata); + vsec->set_entsize(2); + vsec->set_link_section(this->dynsym_section_); + + Output_data_dynamic* const odyn = this->dynamic_data_; + odyn->add_section_address(elfcpp::DT_VERSYM, vsec); + + if (versions->any_defs()) + { + const char* vdname = this->namepool_.add(".gnu.version_d", NULL); + Output_section *vdsec; + vdsec = this->make_output_section(vdname, elfcpp::SHT_GNU_verdef, + elfcpp::SHF_ALLOC); + + unsigned char* vdbuf; + unsigned int vdsize; + unsigned int vdentries; + versions->def_section_contents<size, big_endian>(&this->dynpool_, + &vdbuf, &vdsize, + &vdentries); + + Output_section_data* vddata = new Output_data_const_buffer(vdbuf, + vdsize, + 4); + + vdsec->add_output_section_data(vddata); + vdsec->set_link_section(dynstr); + vdsec->set_info(vdentries); + + odyn->add_section_address(elfcpp::DT_VERDEF, vdsec); + odyn->add_constant(elfcpp::DT_VERDEFNUM, vdentries); + } + + if (versions->any_needs()) + { + const char* vnname = this->namepool_.add(".gnu.version_r", NULL); + Output_section* vnsec; + vnsec = this->make_output_section(vnname, elfcpp::SHT_GNU_verneed, + elfcpp::SHF_ALLOC); + + unsigned char* vnbuf; + unsigned int vnsize; + unsigned int vnentries; + versions->need_section_contents<size, big_endian>(&this->dynpool_, + &vnbuf, &vnsize, + &vnentries); + + Output_section_data* vndata = new Output_data_const_buffer(vnbuf, + vnsize, + 4); + + vnsec->add_output_section_data(vndata); + vnsec->set_link_section(dynstr); + vnsec->set_info(vnentries); + + odyn->add_section_address(elfcpp::DT_VERNEED, vnsec); + odyn->add_constant(elfcpp::DT_VERNEEDNUM, vnentries); + } +} + // Create the .interp section and PT_INTERP segment. void @@ -990,11 +1141,11 @@ Layout::finish_dynamic_section(const Input_objects* input_objects, // FIXME: Support --init and --fini. Symbol* sym = symtab->lookup("_init"); - if (sym != NULL && sym->is_defined() && !sym->is_defined_in_dynobj()) + if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj()) odyn->add_symbol(elfcpp::DT_INIT, sym); sym = symtab->lookup("_fini"); - if (sym != NULL && sym->is_defined() && !sym->is_defined_in_dynobj()) + if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj()) odyn->add_symbol(elfcpp::DT_FINI, sym); // FIXME: Support DT_INIT_ARRAY and DT_FINI_ARRAY. diff --git a/gold/layout.h b/gold/layout.h index 4c54e00..44f9f4e 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -10,6 +10,7 @@ #include "workqueue.h" #include "object.h" +#include "dynobj.h" #include "stringpool.h" namespace gold @@ -201,7 +202,10 @@ class Layout // Create the dynamic symbol table. void - create_dynamic_symtab(const Target*, Symbol_table*); + create_dynamic_symtab(const Target*, Symbol_table*, Output_section** pdynstr, + unsigned int* plocal_dynamic_count, + std::vector<Symbol*>* pdynamic_symbols, + Versions* versions); // Finish the .dynamic section and PT_DYNAMIC segment. void @@ -211,6 +215,20 @@ class Layout void create_interp(const Target* target); + // Create the version sections. + void + create_version_sections(const Target*, const Versions*, + unsigned int local_symcount, + const std::vector<Symbol*>& dynamic_symbols, + const Output_section* dynstr); + + template<int size, bool big_endian> + void + sized_create_version_sections(const Versions* versions, + unsigned int local_symcount, + const std::vector<Symbol*>& dynamic_symbols, + const Output_section* dynstr); + // Return whether to include this section in the link. template<int size, bool big_endian> bool @@ -242,7 +260,7 @@ class Layout off_t set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx); - // Set the final file offsets and section indices of all the + // Set the final file offsets and section indexes of all the // sections not associated with a segment. off_t set_section_offsets(off_t, unsigned int *pshndx); diff --git a/gold/output.h b/gold/output.h index ceea877..013a19f 100644 --- a/gold/output.h +++ b/gold/output.h @@ -1165,7 +1165,7 @@ class Output_section : public Output_data // Set the link field to the output section index of a section. void - set_link_section(Output_data* od) + set_link_section(const Output_data* od) { gold_assert(this->link_ == 0 && !this->should_link_to_symtab_ @@ -1213,7 +1213,7 @@ class Output_section : public Output_data // Set the info field to the output section index of a section. void - set_info_section(Output_data* od) + set_info_section(const Output_data* od) { gold_assert(this->info_ == 0); this->info_section_ = od; @@ -1417,11 +1417,11 @@ class Output_section : public Output_data uint64_t entsize_; // The file offset is in the parent class. // Set the section link field to the index of this section. - Output_data* link_section_; + const Output_data* link_section_; // If link_section_ is NULL, this is the link field. unsigned int link_; // Set the section info field to the index of this section. - Output_data* info_section_; + const Output_data* info_section_; // If info_section_ is NULL, this is the section info field. unsigned int info_; // The section type. diff --git a/gold/po/gold.pot b/gold/po/gold.pot index dbfa857..abce13a 100644 --- a/gold/po/gold.pot +++ b/gold/po/gold.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-12-01 08:46-0800\n" +"POT-Creation-Date: 2006-12-05 15:53-0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -106,56 +106,71 @@ msgstr "" msgid "%s: %s: bad section name offset for section %u: %lu\n" msgstr "" -#: dynobj.cc:398 +#: dynobj.cc:399 #, c-format msgid "%s: %s: duplicate definition for version %u\n" msgstr "" -#: dynobj.cc:442 dynobj.cc:561 +#: dynobj.cc:431 #, c-format -msgid "%s: %s: verdef vd_next field out of range: %u\n" +msgid "%s: %s: unexpected verdef version %u\n" msgstr "" -#: dynobj.cc:466 +#: dynobj.cc:447 #, c-format -msgid "%s: %s: verneed vn_aux field out of range: %u\n" +msgid "%s: %s: verdef vd_cnt field too small: %u\n" msgstr "" -#: dynobj.cc:485 +#: dynobj.cc:456 #, c-format -msgid "%s: %s: verneed vna_next field out of range: %u\n" +msgid "%s: %s: verdef vd_aux field out of range: %u\n" msgstr "" -#: dynobj.cc:498 +#: dynobj.cc:468 #, c-format -msgid "%s: %s: verneed vn_next field out of range: %u\n" +msgid "%s: %s: verdaux vda_name field out of range: %u\n" msgstr "" -#: dynobj.cc:528 +#: dynobj.cc:479 #, c-format -msgid "%s: %s: verdef vd_cnt field too small: %u\n" +msgid "%s: %s: verdef vd_next field out of range: %u\n" msgstr "" -#: dynobj.cc:537 +#: dynobj.cc:513 #, c-format -msgid "%s: %s: verdef vd_aux field out of range: %u\n" +msgid "%s: %s: unexpected verneed version %u\n" msgstr "" -#: dynobj.cc:549 +#: dynobj.cc:524 #, c-format -msgid "%s: %s: verdaux vda_name field out of range: %u\n" +msgid "%s: %s: verneed vn_aux field out of range: %u\n" msgstr "" -#: dynobj.cc:591 +#: dynobj.cc:539 #, c-format msgid "%s: %s: vernaux vna_name field out of range: %u\n" msgstr "" -#: dynobj.cc:628 +#: dynobj.cc:552 +#, c-format +msgid "%s: %s: verneed vna_next field out of range: %u\n" +msgstr "" + +#: dynobj.cc:565 +#, c-format +msgid "%s: %s: verneed vn_next field out of range: %u\n" +msgstr "" + +#: dynobj.cc:613 #, c-format msgid "%s: %s: size of dynamic symbols is not multiple of symbol size\n" msgstr "" +#: dynobj.cc:1240 +#, c-format +msgid "%s: symbol %s has undefined version %s\n" +msgstr "" + #: fileread.cc:55 #, c-format msgid "%s: warning: close(%s) failed: %s" @@ -567,12 +582,12 @@ msgstr "" msgid "%s: %s: reloc section %u size %lu uneven" msgstr "" -#: resolve.cc:142 +#: resolve.cc:147 #, c-format msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n" msgstr "" -#: resolve.cc:148 +#: resolve.cc:153 #, c-format msgid "%s: %s: unsupported symbol binding %d for symbol %s\n" msgstr "" @@ -607,12 +622,12 @@ msgstr "" msgid "%s: %s: versym for symbol %zu has no name: %u\n" msgstr "" -#: symtab.cc:1063 symtab.cc:1235 +#: symtab.cc:1093 symtab.cc:1265 #, c-format msgid "%s: %s: unsupported symbol section 0x%x\n" msgstr "" -#: symtab.cc:1423 +#: symtab.cc:1458 #, c-format msgid "%s: %s: warning: %s\n" msgstr "" diff --git a/gold/reloc.cc b/gold/reloc.cc index 5b4db46..001fb01 100644 --- a/gold/reloc.cc +++ b/gold/reloc.cc @@ -484,7 +484,7 @@ Copy_relocs<size, big_endian>::Copy_reloc_entry::should_emit() { if (this->sym_ == NULL) return false; - if (this->sym_->is_defined_in_dynobj()) + if (this->sym_->is_from_dynobj()) return true; this->sym_ = NULL; return false; diff --git a/gold/resolve.cc b/gold/resolve.cc index b8e5e70..1272e05 100644 --- a/gold/resolve.cc +++ b/gold/resolve.cc @@ -17,10 +17,15 @@ namespace gold template<int size, bool big_endian> void Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym, - Object* object) + Object* object, const char* version) { gold_assert(this->source_ == FROM_OBJECT); this->u_.from_object.object = object; + if (version != NULL && this->version() != version) + { + gold_assert(this->version() == NULL); + this->version_ = version; + } // FIXME: Handle SHN_XINDEX. this->u_.from_object.shndx = sym.get_st_shndx(); this->type_ = sym.get_st_type(); @@ -35,22 +40,22 @@ template<int size> template<bool big_endian> void Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym, - Object* object) + Object* object, const char* version) { - this->override_base(sym, object); + this->override_base(sym, object, version); this->value_ = sym.get_st_value(); this->symsize_ = sym.get_st_size(); } // Resolve a symbol. This is called the second and subsequent times // we see a symbol. TO is the pre-existing symbol. SYM is the new -// symbol, seen in OBJECT. +// symbol, seen in OBJECT. VERSION of the version of SYM. template<int size, bool big_endian> void Symbol_table::resolve(Sized_symbol<size>* to, const elfcpp::Sym<size, big_endian>& sym, - Object* object) + Object* object, const char* version) { if (object->target()->has_resolve()) { @@ -58,7 +63,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, sized_target = object->sized_target SELECT_SIZE_ENDIAN_NAME(size, big_endian) ( SELECT_SIZE_ENDIAN_ONLY(size, big_endian)); - sized_target->resolve(to, sym, object); + sized_target->resolve(to, sym, object, version); return; } @@ -212,7 +217,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, // are currently compatible with the GNU linker. In the future // we should add a target specific option to change this. // FIXME. - to->override(sym, object); + to->override(sym, object, version); return; case DYN_DEF * 16 + DEF: @@ -221,7 +226,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, // definition in a regular object. The definition in the // regular object overrides the definition in the dynamic // object. - to->override(sym, object); + to->override(sym, object, version); return; case UNDEF * 16 + DEF: @@ -230,7 +235,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_WEAK_UNDEF * 16 + DEF: // We've seen an undefined reference, and now we see a // definition. We use the definition. - to->override(sym, object); + to->override(sym, object, version); return; case COMMON * 16 + DEF: @@ -238,9 +243,9 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_COMMON * 16 + DEF: case DYN_WEAK_COMMON * 16 + DEF: // We've seen a common symbol and now we see a definition. The - // definition overrides. FIXME: We should optionally issue a + // definition overrides. FIXME: We should optionally issue, version a // warning. - to->override(sym, object); + to->override(sym, object, version); return; case DEF * 16 + WEAK_DEF: @@ -253,7 +258,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_WEAK_DEF * 16 + WEAK_DEF: // We've seen a dynamic definition and now we see a regular weak // definition. The regular weak definition overrides. - to->override(sym, object); + to->override(sym, object, version); return; case UNDEF * 16 + WEAK_DEF: @@ -261,7 +266,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_UNDEF * 16 + WEAK_DEF: case DYN_WEAK_UNDEF * 16 + WEAK_DEF: // A weak definition of a currently undefined symbol. - to->override(sym, object); + to->override(sym, object, version); return; case COMMON * 16 + WEAK_DEF: @@ -273,7 +278,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_WEAK_COMMON * 16 + WEAK_DEF: // A weak definition does override a definition in a dynamic // object. FIXME: We should optionally issue a warning. - to->override(sym, object); + to->override(sym, object, version); return; case DEF * 16 + DYN_DEF: @@ -288,7 +293,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_UNDEF * 16 + DYN_DEF: case DYN_WEAK_UNDEF * 16 + DYN_DEF: // Use a dynamic definition if we have a reference. - to->override(sym, object); + to->override(sym, object, version); return; case COMMON * 16 + DYN_DEF: @@ -312,7 +317,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_UNDEF * 16 + DYN_WEAK_DEF: case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF: // Use a weak dynamic definition if we have a reference. - to->override(sym, object); + to->override(sym, object, version); return; case COMMON * 16 + DYN_WEAK_DEF: @@ -335,7 +340,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_UNDEF * 16 + UNDEF: case DYN_WEAK_UNDEF * 16 + UNDEF: // A strong undef overrides a dynamic or weak undef. - to->override(sym, object); + to->override(sym, object, version); return; case COMMON * 16 + UNDEF: @@ -399,7 +404,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_WEAK_DEF * 16 + COMMON: // A common symbol does override a weak definition or a dynamic // definition. - to->override(sym, object); + to->override(sym, object, version); return; case UNDEF * 16 + COMMON: @@ -407,7 +412,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_UNDEF * 16 + COMMON: case DYN_WEAK_UNDEF * 16 + COMMON: // A common symbol is a definition for a reference. - to->override(sym, object); + to->override(sym, object, version); return; case COMMON * 16 + COMMON: @@ -419,7 +424,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case WEAK_COMMON * 16 + COMMON: // I'm not sure just what a weak common symbol means, but // presumably it can be overridden by a regular common symbol. - to->override(sym, object); + to->override(sym, object, version); return; case DYN_COMMON * 16 + COMMON: @@ -427,7 +432,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, { // Use the real common symbol, but adjust the size if necessary. typename Sized_symbol<size>::Size_type symsize = to->symsize(); - to->override(sym, object); + to->override(sym, object, version); if (to->symsize() < symsize) to->set_symsize(symsize); } @@ -446,7 +451,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_UNDEF * 16 + WEAK_COMMON: case DYN_WEAK_UNDEF * 16 + WEAK_COMMON: // A weak common symbol is better than an undefined symbol. - to->override(sym, object); + to->override(sym, object, version); return; case COMMON * 16 + WEAK_COMMON: @@ -470,7 +475,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_UNDEF * 16 + DYN_COMMON: case DYN_WEAK_UNDEF * 16 + DYN_COMMON: // A dynamic common symbol is a definition of sorts. - to->override(sym, object); + to->override(sym, object, version); return; case COMMON * 16 + DYN_COMMON: @@ -494,7 +499,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, case DYN_UNDEF * 16 + DYN_WEAK_COMMON: case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON: // I guess a weak common symbol is better than a definition. - to->override(sym, object); + to->override(sym, object, version); return; case COMMON * 16 + DYN_WEAK_COMMON: @@ -520,27 +525,31 @@ void Symbol_table::resolve<32, true>( Sized_symbol<32>* to, const elfcpp::Sym<32, true>& sym, - Object* object); + Object* object, + const char* version); template void Symbol_table::resolve<32, false>( Sized_symbol<32>* to, const elfcpp::Sym<32, false>& sym, - Object* object); + Object* object, + const char* version); template void Symbol_table::resolve<64, true>( Sized_symbol<64>* to, const elfcpp::Sym<64, true>& sym, - Object* object); + Object* object, + const char* version); template void Symbol_table::resolve<64, false>( Sized_symbol<64>* to, const elfcpp::Sym<64, false>& sym, - Object* object); + Object* object, + const char* version); } // End namespace gold. diff --git a/gold/symtab.cc b/gold/symtab.cc index ededad3..5b61152 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -248,8 +248,8 @@ Symbol_table::lookup(const char* name, const char* version) const template<int size, bool big_endian> void -Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from - ACCEPT_SIZE_ENDIAN) +Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from, + const char* version ACCEPT_SIZE_ENDIAN) { unsigned char buf[elfcpp::Elf_sizes<size>::sym_size]; elfcpp::Sym_write<size, big_endian> esym(buf); @@ -259,7 +259,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from esym.put_st_info(from->binding(), from->type()); esym.put_st_other(from->visibility(), from->nonvis()); esym.put_st_shndx(from->shndx()); - Symbol_table::resolve(to, esym.sym(), from->object()); + Symbol_table::resolve(to, esym.sym(), from->object(), version); } // Add one symbol from OBJECT to the symbol table. NAME is symbol @@ -328,7 +328,7 @@ Symbol_table::add_from_object(Object* object, was_undefined = ret->is_undefined(); was_common = ret->is_common(); - Symbol_table::resolve(ret, sym, object); + Symbol_table::resolve(ret, sym, object, version); if (def) { @@ -347,7 +347,7 @@ Symbol_table::add_from_object(Object* object, insdef.first->second SELECT_SIZE(size)); Symbol_table::resolve SELECT_SIZE_ENDIAN_NAME(size, big_endian) ( - ret, sym2 SELECT_SIZE_ENDIAN(size, big_endian)); + ret, sym2, version SELECT_SIZE_ENDIAN(size, big_endian)); this->make_forwarder(insdef.first->second, ret); insdef.first->second = ret; } @@ -363,12 +363,12 @@ Symbol_table::add_from_object(Object* object, if (def && !insdef.second) { - // We already have an entry for NAME/NULL. Make - // NAME/VERSION point to it. + // We already have an entry for NAME/NULL. If we override + // it, then change it to NAME/VERSION. ret = this->get_sized_symbol SELECT_SIZE_NAME(size) ( insdef.first->second SELECT_SIZE(size)); - Symbol_table::resolve(ret, sym, object); + Symbol_table::resolve(ret, sym, object, version); ins.first->second = ret; } else @@ -649,8 +649,8 @@ Symbol_table::add_from_dynobj( template<int size, bool big_endian> Sized_symbol<size>* -Symbol_table::define_special_symbol(Target* target, const char* name, - bool only_if_ref +Symbol_table::define_special_symbol(const Target* target, const char* name, + const char* version, bool only_if_ref ACCEPT_SIZE_ENDIAN) { gold_assert(this->size_ == size); @@ -660,29 +660,34 @@ Symbol_table::define_special_symbol(Target* target, const char* name, if (only_if_ref) { - oldsym = this->lookup(name, NULL); + oldsym = this->lookup(name, version); if (oldsym == NULL || !oldsym->is_undefined()) return NULL; sym = NULL; - // Canonicalize NAME. + // Canonicalize NAME and VERSION. name = oldsym->name(); + version = oldsym->version(); } else { - // Canonicalize NAME. + // Canonicalize NAME and VERSION. Stringpool::Key name_key; name = this->namepool_.add(name, &name_key); + Stringpool::Key version_key = 0; + if (version != NULL) + version = this->namepool_.add(version, &version_key); + Symbol* const snull = NULL; - const Stringpool::Key ver_key = 0; std::pair<typename Symbol_table_type::iterator, bool> ins = - this->table_.insert(std::make_pair(std::make_pair(name_key, ver_key), + this->table_.insert(std::make_pair(std::make_pair(name_key, + version_key), snull)); if (!ins.second) { - // We already have a symbol table entry for NAME. + // We already have a symbol table entry for NAME/VERSION. oldsym = ins.first->second; gold_assert(oldsym != NULL); sym = NULL; @@ -699,7 +704,8 @@ Symbol_table::define_special_symbol(Target* target, const char* name, gold_assert(target->get_size() == size); gold_assert(target->is_big_endian() ? big_endian : !big_endian); typedef Sized_target<size, big_endian> My_target; - My_target* sized_target = static_cast<My_target*>(target); + const My_target* sized_target = + static_cast<const My_target*>(target); sym = sized_target->make_symbol(); if (sym == NULL) return NULL; @@ -737,9 +743,9 @@ Symbol_table::define_special_symbol(Target* target, const char* name, // Define a symbol based on an Output_data. -void -Symbol_table::define_in_output_data(Target* target, const char* name, - Output_data* od, +Symbol* +Symbol_table::define_in_output_data(const Target* target, const char* name, + const char* version, Output_data* od, uint64_t value, uint64_t symsize, elfcpp::STT type, elfcpp::STB binding, elfcpp::STV visibility, @@ -749,13 +755,15 @@ Symbol_table::define_in_output_data(Target* target, const char* name, { gold_assert(target->get_size() == this->size_); if (this->size_ == 32) - this->do_define_in_output_data<32>(target, name, od, value, symsize, - type, binding, visibility, nonvis, - offset_is_from_end, only_if_ref); + return this->do_define_in_output_data<32>(target, name, version, od, value, + symsize, type, binding, + visibility, nonvis, + offset_is_from_end, only_if_ref); else if (this->size_ == 64) - this->do_define_in_output_data<64>(target, name, od, value, symsize, - type, binding, visibility, nonvis, - offset_is_from_end, only_if_ref); + return this->do_define_in_output_data<64>(target, name, version, od, value, + symsize, type, binding, + visibility, nonvis, + offset_is_from_end, only_if_ref); else gold_unreachable(); } @@ -763,10 +771,11 @@ Symbol_table::define_in_output_data(Target* target, const char* name, // Define a symbol in an Output_data, sized version. template<int size> -void +Sized_symbol<size>* Symbol_table::do_define_in_output_data( - Target* target, + const Target* target, const char* name, + const char* version, Output_data* od, typename elfcpp::Elf_types<size>::Elf_Addr value, typename elfcpp::Elf_types<size>::Elf_WXword symsize, @@ -781,25 +790,27 @@ Symbol_table::do_define_in_output_data( if (target->is_big_endian()) sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) ( - target, name, only_if_ref + target, name, version, only_if_ref SELECT_SIZE_ENDIAN(size, true)); else sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) ( - target, name, only_if_ref + target, name, version, only_if_ref SELECT_SIZE_ENDIAN(size, false)); if (sym == NULL) - return; + return NULL; sym->init(name, od, value, symsize, type, binding, visibility, nonvis, offset_is_from_end); + + return sym; } // Define a symbol based on an Output_segment. -void -Symbol_table::define_in_output_segment(Target* target, const char* name, - Output_segment* os, +Symbol* +Symbol_table::define_in_output_segment(const Target* target, const char* name, + const char* version, Output_segment* os, uint64_t value, uint64_t symsize, elfcpp::STT type, elfcpp::STB binding, elfcpp::STV visibility, @@ -809,13 +820,15 @@ Symbol_table::define_in_output_segment(Target* target, const char* name, { gold_assert(target->get_size() == this->size_); if (this->size_ == 32) - this->do_define_in_output_segment<32>(target, name, os, value, symsize, - type, binding, visibility, nonvis, - offset_base, only_if_ref); + return this->do_define_in_output_segment<32>(target, name, version, os, + value, symsize, type, binding, + visibility, nonvis, + offset_base, only_if_ref); else if (this->size_ == 64) - this->do_define_in_output_segment<64>(target, name, os, value, symsize, - type, binding, visibility, nonvis, - offset_base, only_if_ref); + return this->do_define_in_output_segment<64>(target, name, version, os, + value, symsize, type, binding, + visibility, nonvis, + offset_base, only_if_ref); else gold_unreachable(); } @@ -823,10 +836,11 @@ Symbol_table::define_in_output_segment(Target* target, const char* name, // Define a symbol in an Output_segment, sized version. template<int size> -void +Sized_symbol<size>* Symbol_table::do_define_in_output_segment( - Target* target, + const Target* target, const char* name, + const char* version, Output_segment* os, typename elfcpp::Elf_types<size>::Elf_Addr value, typename elfcpp::Elf_types<size>::Elf_WXword symsize, @@ -841,39 +855,41 @@ Symbol_table::do_define_in_output_segment( if (target->is_big_endian()) sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) ( - target, name, only_if_ref + target, name, version, only_if_ref SELECT_SIZE_ENDIAN(size, true)); else sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) ( - target, name, only_if_ref + target, name, version, only_if_ref SELECT_SIZE_ENDIAN(size, false)); if (sym == NULL) - return; + return NULL; sym->init(name, os, value, symsize, type, binding, visibility, nonvis, offset_base); + + return sym; } // Define a special symbol with a constant value. It is a multiple // definition error if this symbol is already defined. -void -Symbol_table::define_as_constant(Target* target, const char* name, - uint64_t value, uint64_t symsize, - elfcpp::STT type, elfcpp::STB binding, - elfcpp::STV visibility, unsigned char nonvis, - bool only_if_ref) +Symbol* +Symbol_table::define_as_constant(const Target* target, const char* name, + const char* version, uint64_t value, + uint64_t symsize, elfcpp::STT type, + elfcpp::STB binding, elfcpp::STV visibility, + unsigned char nonvis, bool only_if_ref) { gold_assert(target->get_size() == this->size_); if (this->size_ == 32) - this->do_define_as_constant<32>(target, name, value, symsize, - type, binding, visibility, nonvis, - only_if_ref); + return this->do_define_as_constant<32>(target, name, version, value, + symsize, type, binding, visibility, + nonvis, only_if_ref); else if (this->size_ == 64) - this->do_define_as_constant<64>(target, name, value, symsize, - type, binding, visibility, nonvis, - only_if_ref); + return this->do_define_as_constant<64>(target, name, version, value, + symsize, type, binding, visibility, + nonvis, only_if_ref); else gold_unreachable(); } @@ -881,10 +897,11 @@ Symbol_table::define_as_constant(Target* target, const char* name, // Define a symbol as a constant, sized version. template<int size> -void +Sized_symbol<size>* Symbol_table::do_define_as_constant( - Target* target, + const Target* target, const char* name, + const char* version, typename elfcpp::Elf_types<size>::Elf_Addr value, typename elfcpp::Elf_types<size>::Elf_WXword symsize, elfcpp::STT type, @@ -897,35 +914,37 @@ Symbol_table::do_define_as_constant( if (target->is_big_endian()) sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) ( - target, name, only_if_ref + target, name, version, only_if_ref SELECT_SIZE_ENDIAN(size, true)); else sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) ( - target, name, only_if_ref + target, name, version, only_if_ref SELECT_SIZE_ENDIAN(size, false)); if (sym == NULL) - return; + return NULL; sym->init(name, value, symsize, type, binding, visibility, nonvis); + + return sym; } // Define a set of symbols in output sections. void -Symbol_table::define_symbols(const Layout* layout, Target* target, int count, - const Define_symbol_in_section* p) +Symbol_table::define_symbols(const Layout* layout, const Target* target, + int count, const Define_symbol_in_section* p) { for (int i = 0; i < count; ++i, ++p) { Output_section* os = layout->find_output_section(p->output_section); if (os != NULL) - this->define_in_output_data(target, p->name, os, p->value, p->size, - p->type, p->binding, p->visibility, - p->nonvis, p->offset_is_from_end, - p->only_if_ref); + this->define_in_output_data(target, p->name, NULL, os, p->value, + p->size, p->type, p->binding, + p->visibility, p->nonvis, + p->offset_is_from_end, p->only_if_ref); else - this->define_as_constant(target, p->name, 0, p->size, p->type, + this->define_as_constant(target, p->name, NULL, 0, p->size, p->type, p->binding, p->visibility, p->nonvis, p->only_if_ref); } @@ -934,8 +953,8 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count, // Define a set of symbols in output segments. void -Symbol_table::define_symbols(const Layout* layout, Target* target, int count, - const Define_symbol_in_segment* p) +Symbol_table::define_symbols(const Layout* layout, const Target* target, + int count, const Define_symbol_in_segment* p) { for (int i = 0; i < count; ++i, ++p) { @@ -943,12 +962,12 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count, p->segment_flags_set, p->segment_flags_clear); if (os != NULL) - this->define_in_output_segment(target, p->name, os, p->value, p->size, - p->type, p->binding, p->visibility, - p->nonvis, p->offset_base, - p->only_if_ref); + this->define_in_output_segment(target, p->name, NULL, os, p->value, + p->size, p->type, p->binding, + p->visibility, p->nonvis, + p->offset_base, p->only_if_ref); else - this->define_as_constant(target, p->name, 0, p->size, p->type, + this->define_as_constant(target, p->name, NULL, 0, p->size, p->type, p->binding, p->visibility, p->nonvis, p->only_if_ref); } @@ -960,9 +979,12 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count, // updated dynamic symbol index. unsigned int -Symbol_table::set_dynsym_indexes(unsigned int index, +Symbol_table::set_dynsym_indexes(const General_options* options, + const Target* target, + unsigned int index, std::vector<Symbol*>* syms, - Stringpool* dynpool) + Stringpool* dynpool, + Versions* versions) { for (Symbol_table_type::iterator p = this->table_.begin(); p != this->table_.end(); @@ -982,9 +1004,17 @@ Symbol_table::set_dynsym_indexes(unsigned int index, ++index; syms->push_back(sym); dynpool->add(sym->name(), NULL); + + // Record any version information. + if (sym->version() != NULL) + versions->record_version(options, dynpool, sym); } } + // Finish up the versions. In some cases this may add new dynamic + // symbols. + index = versions->finalize(target, this, index, syms); + return index; } diff --git a/gold/symtab.h b/gold/symtab.h index f7a5c4c..6e4344d4 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -24,6 +24,7 @@ class Sized_relobj; class Dynobj; template<int size, bool big_endian> class Sized_dynobj; +class Versions; class Output_data; class Output_section; class Output_segment; @@ -303,13 +304,11 @@ class Symbol && this->shndx() != elfcpp::SHN_COMMON)); } - // Return whether this symbol is defined in a dynamic object. + // Return true if this symbol is from a dynamic object. bool - is_defined_in_dynobj() const + is_from_dynobj() const { - return (this->source_ == FROM_OBJECT - && this->object()->is_dynamic() - && this->is_defined()); + return this->source_ == FROM_OBJECT && this->object()->is_dynamic(); } // Return whether this is an undefined symbol. @@ -376,7 +375,8 @@ class Symbol // Override existing symbol. template<int size, bool big_endian> void - override_base(const elfcpp::Sym<size, big_endian>&, Object* object); + override_base(const elfcpp::Sym<size, big_endian>&, Object* object, + const char* version); private: Symbol(const Symbol&); @@ -518,7 +518,8 @@ class Sized_symbol : public Symbol // Override existing symbol. template<bool big_endian> void - override(const elfcpp::Sym<size, big_endian>&, Object* object); + override(const elfcpp::Sym<size, big_endian>&, Object* object, + const char* version); // Return the symbol's value. Value_type @@ -730,25 +731,20 @@ class Symbol_table const unsigned char* versym, size_t versym_size, const std::vector<const char*>*); - // Define a special symbol. - template<int size, bool big_endian> - Sized_symbol<size>* - define_special_symbol(Target* target, const char* name, bool only_if_ref - ACCEPT_SIZE_ENDIAN); - // Define a special symbol based on an Output_data. It is a // multiple definition error if this symbol is already defined. - void - define_in_output_data(Target*, const char* name, Output_data*, - uint64_t value, uint64_t symsize, + Symbol* + define_in_output_data(const Target*, const char* name, const char* version, + Output_data*, uint64_t value, uint64_t symsize, elfcpp::STT type, elfcpp::STB binding, elfcpp::STV visibility, unsigned char nonvis, bool offset_is_from_end, bool only_if_ref); // Define a special symbol based on an Output_segment. It is a // multiple definition error if this symbol is already defined. - void - define_in_output_segment(Target*, const char* name, Output_segment*, + Symbol* + define_in_output_segment(const Target*, const char* name, + const char* version, Output_segment*, uint64_t value, uint64_t symsize, elfcpp::STT type, elfcpp::STB binding, elfcpp::STV visibility, unsigned char nonvis, @@ -756,20 +752,20 @@ class Symbol_table // Define a special symbol with a constant value. It is a multiple // definition error if this symbol is already defined. - void - define_as_constant(Target*, const char* name, uint64_t value, - uint64_t symsize, elfcpp::STT type, elfcpp::STB binding, - elfcpp::STV visibility, unsigned char nonvis, - bool only_if_ref); + Symbol* + define_as_constant(const Target*, const char* name, const char* version, + uint64_t value, uint64_t symsize, elfcpp::STT type, + elfcpp::STB binding, elfcpp::STV visibility, + unsigned char nonvis, bool only_if_ref); // Define a set of symbols in output sections. void - define_symbols(const Layout*, Target*, int count, + define_symbols(const Layout*, const Target*, int count, const Define_symbol_in_section*); // Define a set of symbols in output segments. void - define_symbols(const Layout*, Target*, int count, + define_symbols(const Layout*, const Target*, int count, const Define_symbol_in_segment*); // Look up a symbol. @@ -824,8 +820,8 @@ class Symbol_table // the vector. The names are stored into the Stringpool. This // returns an updated dynamic symbol index. unsigned int - set_dynsym_indexes(unsigned int index, std::vector<Symbol*>*, - Stringpool*); + set_dynsym_indexes(const General_options*, const Target*, unsigned int index, + std::vector<Symbol*>*, Stringpool*, Versions*); // Finalize the symbol table after we have set the final addresses // of all the input sections. This sets the final symbol indexes, @@ -874,17 +870,25 @@ class Symbol_table static void resolve(Sized_symbol<size>* to, const elfcpp::Sym<size, big_endian>& sym, - Object*); + Object*, const char* version); template<int size, bool big_endian> static void - resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from - ACCEPT_SIZE_ENDIAN); + resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from, + const char* version ACCEPT_SIZE_ENDIAN); + + // Define a special symbol. + template<int size, bool big_endian> + Sized_symbol<size>* + define_special_symbol(const Target* target, const char* name, + const char* version, bool only_if_ref + ACCEPT_SIZE_ENDIAN); // Define a symbol in an Output_data, sized version. template<int size> - void - do_define_in_output_data(Target*, const char* name, Output_data*, + Sized_symbol<size>* + do_define_in_output_data(const Target*, const char* name, + const char* version, Output_data*, typename elfcpp::Elf_types<size>::Elf_Addr value, typename elfcpp::Elf_types<size>::Elf_WXword ssize, elfcpp::STT type, elfcpp::STB binding, @@ -893,9 +897,9 @@ class Symbol_table // Define a symbol in an Output_segment, sized version. template<int size> - void + Sized_symbol<size>* do_define_in_output_segment( - Target*, const char* name, Output_segment* os, + const Target*, const char* name, const char* version, Output_segment* os, typename elfcpp::Elf_types<size>::Elf_Addr value, typename elfcpp::Elf_types<size>::Elf_WXword ssize, elfcpp::STT type, elfcpp::STB binding, @@ -904,9 +908,9 @@ class Symbol_table // Define a symbol as a constant, sized version. template<int size> - void + Sized_symbol<size>* do_define_as_constant( - Target*, const char* name, + const Target*, const char* name, const char* version, typename elfcpp::Elf_types<size>::Elf_Addr value, typename elfcpp::Elf_types<size>::Elf_WXword ssize, elfcpp::STT type, elfcpp::STB binding, diff --git a/gold/target.h b/gold/target.h index 42bed9e..9181a93 100644 --- a/gold/target.h +++ b/gold/target.h @@ -145,15 +145,17 @@ class Sized_target : public Target // symbol table. This will only be called if has_make_symbol() // returns true. virtual Sized_symbol<size>* - make_symbol() + make_symbol() const { gold_unreachable(); } // Resolve a symbol for the target. This should be overridden by a // target which needs to take special action. TO is the // pre-existing symbol. SYM is the new symbol, seen in OBJECT. - // This will only be called if has_resolve() returns true. + // VERSION is the version of SYM. This will only be called if + // has_resolve() returns true. virtual void - resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*) + resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*, + const char*) { gold_unreachable(); } // Scan the relocs for a section, and record any information |