diff options
-rw-r--r-- | gold/ChangeLog | 34 | ||||
-rw-r--r-- | gold/layout.cc | 61 | ||||
-rw-r--r-- | gold/layout.h | 214 | ||||
-rw-r--r-- | gold/object.cc | 182 | ||||
-rw-r--r-- | gold/object.h | 31 | ||||
-rw-r--r-- | gold/plugin.cc | 9 |
6 files changed, 366 insertions, 165 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 974a49f..8262c60 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,37 @@ +2009-07-16 Ian Lance Taylor <iant@google.com> + + PR 10400 + * layout.h: #include <map>. + (class Kept_section): Change from struct to class. Add accessors + and setters. Add section size to Comdat_group mapping. Change + Comdat_group to std::map. Add is_comdat_ field. Add + linkonce_size field in union. + (class Layout): Update declaration of find_or_add_kept_section. + Don't declare find_kept_object. + * layout.cc (Layout::find_or_add_kept_section): Remove candidate + parameter. Add object, shndx, is_comdat, and is_group_name + parameters. Change all callers. Adjust for new Kept_section. + (Layout::find_kept_object): Remove. + * object.cc (Sized_relobj::include_section_group): Update use of + Kept_section. Rename secnum to shndx. Only record + Kept_comdat_section if sections are the same size. + (Sized_relobj::include_linkonce_section): Update use of + Kept_section. Only record Kept_comdat_section if sections are the + same size. Set size of linkonce section. + (Sized_relobj::map_to_kept_section): Update call to + get_kept_comdat_section. + * object.h (class Sized_relobj): Rename fields in + Kept_comdat_section to drop trailing underscores; change object + field to Relobj*. Change Kept_comdat_section_table to store + struct rather than pointer. + (Sized_relobj::set_kept_comdat_section): Remove kept parameter. + Add kept_object and kept_shndx parameters. Change all callers. + (Sized_relobj::get_kept_comdat_section): Change return type to + bool. Add kept_object and kept_shndx parameters. Change all + callers. + * plugin.cc (Pluginobj::include_comdat_group): Update call to + Layout::find_or_add_kept_section. + 2009-07-09 Ian Lance Taylor <iant@google.com> * merge.cc (Object_merge_map::initialize_input_to_output_map): diff --git a/gold/layout.cc b/gold/layout.cc index e8625d2..0093c29 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -3045,16 +3045,18 @@ Layout::output_section_name(const char* name, size_t* plen) // Check if a comdat group or .gnu.linkonce section with the given // NAME is selected for the link. If there is already a section, -// *KEPT_SECTION is set to point to the signature and the function -// returns false. Otherwise, the CANDIDATE signature is recorded for -// this NAME in the layout object, *KEPT_SECTION is set to the -// internal copy and the function return false. In some cases, with -// CANDIDATE->GROUP_ being false, KEPT_SECTION can point back to -// CANDIDATE. +// *KEPT_SECTION is set to point to the existing section and the +// function returns false. Otherwise, OBJECT, SHNDX, IS_COMDAT, and +// IS_GROUP_NAME are recorded for this NAME in the layout object, +// *KEPT_SECTION is set to the internal copy and the function returns +// true. bool Layout::find_or_add_kept_section(const std::string& name, - Kept_section* candidate, + Relobj* object, + unsigned int shndx, + bool is_comdat, + bool is_group_name, Kept_section** kept_section) { // It's normal to see a couple of entries here, for the x86 thunk @@ -3068,36 +3070,46 @@ Layout::find_or_add_kept_section(const std::string& name, this->resized_signatures_ = true; } - std::pair<Signatures::iterator, bool> ins( - this->signatures_.insert(std::make_pair(name, *candidate))); + Kept_section candidate; + std::pair<Signatures::iterator, bool> ins = + this->signatures_.insert(std::make_pair(name, candidate)); - if (kept_section) + if (kept_section != NULL) *kept_section = &ins.first->second; if (ins.second) { // This is the first time we've seen this signature. + ins.first->second.set_object(object); + ins.first->second.set_shndx(shndx); + if (is_comdat) + ins.first->second.set_is_comdat(); + if (is_group_name) + ins.first->second.set_is_group_name(); return true; } - if (ins.first->second.is_group) + // We have already seen this signature. + + if (ins.first->second.is_group_name()) { // We've already seen a real section group with this signature. - // If the kept group is from a plugin object, and we're in - // the replacement phase, accept the new one as a replacement. - if (ins.first->second.object == NULL + // If the kept group is from a plugin object, and we're in the + // replacement phase, accept the new one as a replacement. + if (ins.first->second.object() == NULL && parameters->options().plugins()->in_replacement_phase()) { - ins.first->second = *candidate; + ins.first->second.set_object(object); + ins.first->second.set_shndx(shndx); return true; } return false; } - else if (candidate->is_group) + else if (is_group_name) { // This is a real section group, and we've already seen a // linkonce section with this signature. Record that we've seen // a section group, and don't include this section group. - ins.first->second.is_group = true; + ins.first->second.set_is_group_name(); return false; } else @@ -3105,25 +3117,10 @@ Layout::find_or_add_kept_section(const std::string& name, // We've already seen a linkonce section and this is a linkonce // section. These don't block each other--this may be the same // symbol name with different section types. - *kept_section = candidate; return true; } } -// Find the given comdat signature, and return the object and section -// index of the kept group. -Relobj* -Layout::find_kept_object(const std::string& signature, - unsigned int* pshndx) const -{ - Signatures::const_iterator p = this->signatures_.find(signature); - if (p == this->signatures_.end()) - return NULL; - if (pshndx != NULL) - *pshndx = p->second.shndx; - return p->second.object; -} - // Store the allocated sections into the section list. void diff --git a/gold/layout.h b/gold/layout.h index 86234a1..0affa81 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -25,6 +25,7 @@ #include <cstring> #include <list> +#include <map> #include <string> #include <utility> #include <vector> @@ -90,35 +91,192 @@ class Layout_task_runner : public Task_function_runner Mapfile* mapfile_; }; -// This struct holds information about the comdat or .gnu.linkonce -// that will be kept. +// This class holds information about the comdat group or +// .gnu.linkonce section that will be kept for a given signature. -struct Kept_section +class Kept_section { + private: + // For a comdat group, we build a mapping from the name of each + // section in the group to the section index and the size in object. + // When we discard a group in some other object file, we use this + // map to figure out which kept section the discarded section is + // associated with. We then use that mapping when processing relocs + // against discarded sections. + struct Comdat_section_info + { + // The section index. + unsigned int shndx; + // The section size. + uint64_t size; + + Comdat_section_info(unsigned int a_shndx, uint64_t a_size) + : shndx(a_shndx), size(a_size) + { } + }; + + // Most comdat groups have only one or two sections, so we use a + // std::map rather than an Unordered_map to optimize for that case + // without paying too heavily for groups with more sections. + typedef std::map<std::string, Comdat_section_info> Comdat_group; + + public: Kept_section() - : object(NULL), shndx(0), is_group(false), group_sections(NULL) - { } - Kept_section(Relobj* a_object, unsigned int a_shndx, bool a_is_group) - : object(a_object), shndx(a_shndx), is_group(a_is_group), - group_sections(NULL) - { } + : object_(NULL), shndx_(0), is_comdat_(false), is_group_name_(false) + { this->u_.linkonce_size = 0; } + + // We need to support copies for the signature map in the Layout + // object, but we should never copy an object after it has been + // marked as a comdat section. + Kept_section(const Kept_section& k) + : object_(k.object_), shndx_(k.shndx_), is_comdat_(false), + is_group_name_(k.is_group_name_) + { + gold_assert(!k.is_comdat_); + this->u_.linkonce_size = 0; + } + + ~Kept_section() + { + if (this->is_comdat_) + delete this->u_.group_sections; + } + + // The object where this section lives. + Relobj* + object() const + { return this->object_; } + + // Set the object. + void + set_object(Relobj* object) + { + gold_assert(this->object_ == NULL); + this->object_ = object; + } + + // The section index. + unsigned int + shndx() const + { return this->shndx_; } + + // Set the section index. + void + set_shndx(unsigned int shndx) + { + gold_assert(this->shndx_ == 0); + this->shndx_ = shndx; + } + + // Whether this is a comdat group. + bool + is_comdat() const + { return this->is_comdat_; } + + // Set that this is a comdat group. + void + set_is_comdat() + { + gold_assert(!this->is_comdat_); + this->is_comdat_ = true; + this->u_.group_sections = new Comdat_group(); + } + + // Whether this is associated with the name of a group or section + // rather than the symbol name derived from a linkonce section. + bool + is_group_name() const + { return this->is_group_name_; } + + // Note that this represents a comdat group rather than a single + // linkonce section. + void + set_is_group_name() + { this->is_group_name_ = true; } + + // Add a section to the group list. + void + add_comdat_section(const std::string& name, unsigned int shndx, + uint64_t size) + { + gold_assert(this->is_comdat_); + Comdat_section_info sinfo(shndx, size); + this->u_.group_sections->insert(std::make_pair(name, sinfo)); + } + + // Look for a section name in the group list, and return whether it + // was found. If found, returns the section index and size. + bool + find_comdat_section(const std::string& name, unsigned int *pshndx, + uint64_t *psize) const + { + gold_assert(this->is_comdat_); + Comdat_group::const_iterator p = this->u_.group_sections->find(name); + if (p == this->u_.group_sections->end()) + return false; + *pshndx = p->second.shndx; + *psize = p->second.size; + return true; + } - typedef Unordered_map<std::string, unsigned int> Comdat_group; + // If there is only one section in the group list, return true, and + // return the section index and size. + bool + find_single_comdat_section(unsigned int *pshndx, uint64_t *psize) const + { + gold_assert(this->is_comdat_); + if (this->u_.group_sections->size() != 1) + return false; + Comdat_group::const_iterator p = this->u_.group_sections->begin(); + *pshndx = p->second.shndx; + *psize = p->second.size; + return true; + } + + // Return the size of a linkonce section. + uint64_t + linkonce_size() const + { + gold_assert(!this->is_comdat_); + return this->u_.linkonce_size; + } - // The object containing the comdat or .gnu.linkonce. - Relobj* object; - // Index to the group section for comdats and the section itself for + // Set the size of a linkonce section. + void + set_linkonce_size(uint64_t size) + { + gold_assert(!this->is_comdat_); + this->u_.linkonce_size = size; + } + + private: + // No assignment. + Kept_section& operator=(const Kept_section&); + + // The object containing the comdat group or .gnu.linkonce section. + Relobj* object_; + // Index of the group section for comdats and the section itself for // .gnu.linkonce. - unsigned int shndx; + unsigned int shndx_; + // True if this is for a comdat group rather than a .gnu.linkonce + // section. + bool is_comdat_; // The Kept_sections are values of a mapping, that maps names to // them. This field is true if this struct is associated with the // name of a comdat or .gnu.linkonce, false if it is associated with // the name of a symbol obtained from the .gnu.linkonce.* name // through some heuristics. - bool is_group; - // For comdats, a map from names of the sections in the group to - // indexes in OBJECT_. NULL for .gnu.linkonce. - Comdat_group* group_sections; + bool is_group_name_; + union + { + // If the is_comdat_ field is true, this holds a map from names of + // the sections in the group to section indexes in object_ and to + // section sizes. + Comdat_group* group_sections; + // If the is_comdat_ field is false, this holds the size of the + // single section. + uint64_t linkonce_size; + } u_; }; // This class handles the details of laying out input sections. @@ -270,20 +428,14 @@ class Layout // Check if a comdat group or .gnu.linkonce section with the given // NAME is selected for the link. If there is already a section, // *KEPT_SECTION is set to point to the signature and the function - // returns false. Otherwise, the CANDIDATE signature is recorded - // for this NAME in the layout object, *KEPT_SECTION is set to the - // internal copy and the function return false. In some cases, with - // CANDIDATE->GROUP_ being false, KEPT_SECTION can point back to - // CANDIDATE. + // returns false. Otherwise, OBJECT, SHNDX,IS_COMDAT, and + // IS_GROUP_NAME are recorded for this NAME in the layout object, + // *KEPT_SECTION is set to the internal copy and the function return + // false. bool - find_or_add_kept_section(const std::string& name, - Kept_section* candidate, - Kept_section** kept_section); - - // Find the given comdat signature, and return the object and section - // index of the kept group. - Relobj* - find_kept_object(const std::string&, unsigned int*) const; + find_or_add_kept_section(const std::string& name, Relobj* object, + unsigned int shndx, bool is_comdat, + bool is_group_name, Kept_section** kept_section); // Finalize the layout after all the input sections have been added. off_t diff --git a/gold/object.cc b/gold/object.cc index 75e5a2e..1b964d7 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -686,24 +686,20 @@ Sized_relobj<size, big_endian>::include_section_group( // Record this section group in the layout, and see whether we've already // seen one with the same signature. bool include_group; - Sized_relobj<size, big_endian>* kept_object = NULL; - Kept_section::Comdat_group* kept_group = NULL; + bool is_comdat; + Kept_section* kept_section = NULL; if ((flags & elfcpp::GRP_COMDAT) == 0) - include_group = true; + { + include_group = true; + is_comdat = false; + } else { - Kept_section this_group(this, index, true); - Kept_section *kept_section_group; include_group = layout->find_or_add_kept_section(signature, - &this_group, - &kept_section_group); - if (include_group) - kept_section_group->group_sections = new Kept_section::Comdat_group; - - kept_group = kept_section_group->group_sections; - kept_object = (static_cast<Sized_relobj<size, big_endian>*> - (kept_section_group->object)); + this, index, true, + true, &kept_section); + is_comdat = true; } size_t count = shdr.get_sh_size() / sizeof(elfcpp::Elf_Word); @@ -715,27 +711,27 @@ Sized_relobj<size, big_endian>::include_section_group( for (size_t i = 1; i < count; ++i) { - elfcpp::Elf_Word secnum = + elfcpp::Elf_Word shndx = this->adjust_shndx(elfcpp::Swap<32, big_endian>::readval(pword + i)); if (relocate_group) - shndxes.push_back(secnum); + shndxes.push_back(shndx); - if (secnum >= this->shnum()) + if (shndx >= this->shnum()) { this->error(_("section %u in section group %u out of range"), - secnum, index); + shndx, index); continue; } // Check for an earlier section number, since we're going to get // it wrong--we may have already decided to include the section. - if (secnum < index) + if (shndx < index) this->error(_("invalid section group %u refers to earlier section %u"), - index, secnum); + index, shndx); // Get the name of the member section. - typename This::Shdr member_shdr(shdrs + secnum * This::shdr_size); + typename This::Shdr member_shdr(shdrs + shndx * This::shdr_size); if (member_shdr.get_sh_name() >= section_names_size) { // This is an error, but it will be diagnosed eventually @@ -745,29 +741,53 @@ Sized_relobj<size, big_endian>::include_section_group( } std::string mname(section_names + member_shdr.get_sh_name()); - if (!include_group) + if (include_group) + { + if (is_comdat) + kept_section->add_comdat_section(mname, shndx, + member_shdr.get_sh_size()); + } + else { - (*omit)[secnum] = true; - if (kept_group != NULL) + (*omit)[shndx] = true; + + if (is_comdat) { - // Find the corresponding kept section, and store that info - // in the discarded section table. - Kept_section::Comdat_group::const_iterator p = - kept_group->find(mname); - if (p != kept_group->end()) - { - Kept_comdat_section* kept = - new Kept_comdat_section(kept_object, p->second); - this->set_kept_comdat_section(secnum, kept); - } + Relobj* kept_object = kept_section->object(); + if (kept_section->is_comdat()) + { + // Find the corresponding kept section, and store + // that info in the discarded section table. + unsigned int kept_shndx; + uint64_t kept_size; + if (kept_section->find_comdat_section(mname, &kept_shndx, + &kept_size)) + { + // We don't keep a mapping for this section if + // it has a different size. The mapping is only + // used for relocation processing, and we don't + // want to treat the sections as similar if the + // sizes are different. Checking the section + // size is the approach used by the GNU linker. + if (kept_size == member_shdr.get_sh_size()) + this->set_kept_comdat_section(shndx, kept_object, + kept_shndx); + } + } + else + { + // The existing section is a linkonce section. Add + // a mapping if there is exactly one section in the + // group (which is true when COUNT == 2) and if it + // is the same size. + if (count == 2 + && (kept_section->linkonce_size() + == member_shdr.get_sh_size())) + this->set_kept_comdat_section(shndx, kept_object, + kept_section->shndx()); + } } } - else if (flags & elfcpp::GRP_COMDAT) - { - // Add the section to the kept group table. - gold_assert(kept_group != NULL); - kept_group->insert(std::make_pair(mname, secnum)); - } } if (relocate_group) @@ -798,8 +818,9 @@ Sized_relobj<size, big_endian>::include_linkonce_section( Layout* layout, unsigned int index, const char* name, - const elfcpp::Shdr<size, big_endian>&) + const elfcpp::Shdr<size, big_endian>& shdr) { + typename elfcpp::Elf_types<size>::Elf_WXword sh_size = shdr.get_sh_size(); // In general the symbol name we want will be the string following // the last '.'. However, we have to handle the case of // .gnu.linkonce.t.__i686.get_pc_thunk.bx, which was generated by @@ -816,29 +837,24 @@ Sized_relobj<size, big_endian>::include_linkonce_section( symname = strrchr(name, '.') + 1; std::string sig1(symname); std::string sig2(name); - Kept_section candidate1(this, index, false); - Kept_section candidate2(this, index, true); Kept_section* kept1; Kept_section* kept2; - bool include1 = layout->find_or_add_kept_section(sig1, &candidate1, &kept1); - bool include2 = layout->find_or_add_kept_section(sig2, &candidate2, &kept2); + bool include1 = layout->find_or_add_kept_section(sig1, this, index, false, + false, &kept1); + bool include2 = layout->find_or_add_kept_section(sig2, this, index, false, + true, &kept2); if (!include2) { - // The section is being discarded on the basis of its section - // name (i.e., the kept section was also a linkonce section). - // In this case, the section index stored with the layout object - // is the linkonce section that was kept. - unsigned int kept_group_index = kept2->shndx; - Relobj* kept_relobj = kept2->object; - if (kept_relobj != NULL) - { - Sized_relobj<size, big_endian>* kept_object = - static_cast<Sized_relobj<size, big_endian>*>(kept_relobj); - Kept_comdat_section* kept = - new Kept_comdat_section(kept_object, kept_group_index); - this->set_kept_comdat_section(index, kept); - } + // We are not including this section because we already saw the + // name of the section as a signature. This normally implies + // that the kept section is another linkonce section. If it is + // the same size, record it as the section which corresponds to + // this one. + if (kept2->object() != NULL + && !kept2->is_comdat() + && kept2->linkonce_size() == sh_size) + this->set_kept_comdat_section(index, kept2->object(), kept2->shndx()); } else if (!include1) { @@ -849,22 +865,18 @@ Sized_relobj<size, big_endian>::include_linkonce_section( // this linkonce section. We'll handle the simple case where // the group has only one member section. Otherwise, it's not // worth the effort. - Relobj* kept_relobj = kept1->object; - if (kept_relobj != NULL) - { - Sized_relobj<size, big_endian>* kept_object = - static_cast<Sized_relobj<size, big_endian>*>(kept_relobj); - Kept_section::Comdat_group* kept_group = kept1->group_sections; - if (kept_group != NULL && kept_group->size() == 1) - { - Kept_section::Comdat_group::const_iterator p = - kept_group->begin(); - gold_assert(p != kept_group->end()); - Kept_comdat_section* kept = - new Kept_comdat_section(kept_object, p->second); - this->set_kept_comdat_section(index, kept); - } - } + unsigned int kept_shndx; + uint64_t kept_size; + if (kept1->object() != NULL + && kept1->is_comdat() + && kept1->find_single_comdat_section(&kept_shndx, &kept_size) + && kept_size == sh_size) + this->set_kept_comdat_section(index, kept1->object(), kept_shndx); + } + else + { + kept1->set_linkonce_size(sh_size); + kept2->set_linkonce_size(sh_size); } return include1 && include2; @@ -1216,7 +1228,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab, out_sections[i] = reinterpret_cast<Output_section*>(2); out_section_offsets[i] = invalid_address; continue; - } + } // During gc_pass_two if a section that was previously deferred is // found, do not layout the section as layout_deferred_sections will // do it later from gold.cc. @@ -1915,15 +1927,19 @@ Sized_relobj<size, big_endian>::map_to_kept_section( unsigned int shndx, bool* found) const { - Kept_comdat_section *kept = this->get_kept_comdat_section(shndx); - if (kept != NULL) - { - gold_assert(kept->object_ != NULL); - *found = true; - Output_section* os = kept->object_->output_section(kept->shndx_); - Address offset = kept->object_->get_output_section_offset(kept->shndx_); + Relobj* kept_object; + unsigned int kept_shndx; + if (this->get_kept_comdat_section(shndx, &kept_object, &kept_shndx)) + { + Sized_relobj<size, big_endian>* kept_relobj = + static_cast<Sized_relobj<size, big_endian>*>(kept_object); + Output_section* os = kept_relobj->output_section(kept_shndx); + Address offset = kept_relobj->get_output_section_offset(kept_shndx); if (os != NULL && offset != invalid_address) - return os->address() + offset; + { + *found = true; + return os->address() + offset; + } } *found = false; return 0; diff --git a/gold/object.h b/gold/object.h index d5f111f..dc6a156 100644 --- a/gold/object.h +++ b/gold/object.h @@ -1590,14 +1590,13 @@ class Sized_relobj : public Relobj // kept section. struct Kept_comdat_section { - Kept_comdat_section(Sized_relobj<size, big_endian>* object, - unsigned int shndx) - : object_(object), shndx_(shndx) + Kept_comdat_section(Relobj* a_object, unsigned int a_shndx) + : object(a_object), shndx(a_shndx) { } - Sized_relobj<size, big_endian>* object_; - unsigned int shndx_; + Relobj* object; + unsigned int shndx; }; - typedef std::map<unsigned int, Kept_comdat_section*> + typedef std::map<unsigned int, Kept_comdat_section> Kept_comdat_section_table; // Adjust a section index if necessary. @@ -1729,20 +1728,26 @@ class Sized_relobj : public Relobj // Record a mapping from discarded section SHNDX to the corresponding // kept section. void - set_kept_comdat_section(unsigned int shndx, Kept_comdat_section* kept) + set_kept_comdat_section(unsigned int shndx, Relobj* kept_object, + unsigned int kept_shndx) { - this->kept_comdat_sections_[shndx] = kept; + Kept_comdat_section kept(kept_object, kept_shndx); + this->kept_comdat_sections_.insert(std::make_pair(shndx, kept)); } - // Find the kept section corresponding to the discarded section SHNDX. - Kept_comdat_section* - get_kept_comdat_section(unsigned int shndx) const + // Find the kept section corresponding to the discarded section + // SHNDX. Return true if found. + bool + get_kept_comdat_section(unsigned int shndx, Relobj** kept_object, + unsigned int* kept_shndx) const { typename Kept_comdat_section_table::const_iterator p = this->kept_comdat_sections_.find(shndx); if (p == this->kept_comdat_sections_.end()) - return NULL; - return p->second; + return false; + *kept_object = p->second.object; + *kept_shndx = p->second.shndx; + return true; } // The GOT offsets of local symbols. This map also stores GOT offsets diff --git a/gold/plugin.cc b/gold/plugin.cc index b1007a7..2a21b8f 100644 --- a/gold/plugin.cc +++ b/gold/plugin.cc @@ -509,12 +509,9 @@ Pluginobj::include_comdat_group(std::string comdat_key, Layout* layout) // If this is the first time we've seen this comdat key, ask the // layout object whether it should be included. if (ins.second) - { - Kept_section to_add(NULL, 1, true); - ins.first->second = layout->find_or_add_kept_section(comdat_key, - &to_add, - NULL); - } + ins.first->second = layout->find_or_add_kept_section(comdat_key, + NULL, 0, true, + true, NULL); return ins.first->second; } |