diff options
author | Ian Lance Taylor <iant@google.com> | 2007-05-16 17:42:48 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@google.com> | 2007-05-16 17:42:48 +0000 |
commit | b8e6aad9606384125f588d531c567f49bad346e2 (patch) | |
tree | e1172d50384713b91c329cc88cabcd2728f929a9 | |
parent | 60dfee729999b913a247956c4816e758afb86a4b (diff) | |
download | binutils-gdb-b8e6aad9606384125f588d531c567f49bad346e2.tar.gz |
Add support for SHF_MERGE sections.
-rw-r--r-- | gold/Makefile.am | 2 | ||||
-rw-r--r-- | gold/Makefile.in | 12 | ||||
-rw-r--r-- | gold/dynobj.h | 1 | ||||
-rw-r--r-- | gold/i386.cc | 55 | ||||
-rw-r--r-- | gold/layout.cc | 11 | ||||
-rw-r--r-- | gold/merge.cc | 333 | ||||
-rw-r--r-- | gold/merge.h | 226 | ||||
-rw-r--r-- | gold/object.cc | 61 | ||||
-rw-r--r-- | gold/object.h | 146 | ||||
-rw-r--r-- | gold/output.cc | 155 | ||||
-rw-r--r-- | gold/output.h | 185 | ||||
-rw-r--r-- | gold/po/POTFILES.in | 2 | ||||
-rw-r--r-- | gold/po/gold.pot | 83 | ||||
-rw-r--r-- | gold/reloc.cc | 3 | ||||
-rw-r--r-- | gold/reloc.h | 136 | ||||
-rw-r--r-- | gold/stringpool.cc | 222 | ||||
-rw-r--r-- | gold/stringpool.h | 71 | ||||
-rw-r--r-- | gold/target-reloc.h | 14 |
18 files changed, 1451 insertions, 267 deletions
diff --git a/gold/Makefile.am b/gold/Makefile.am index 02a6da11f63..a411127df94 100644 --- a/gold/Makefile.am +++ b/gold/Makefile.am @@ -30,6 +30,7 @@ CCFILES = \ gold.cc \ gold-threads.cc \ layout.cc \ + merge.cc \ object.cc \ options.cc \ output.cc \ @@ -52,6 +53,7 @@ HFILES = \ gold.h \ gold-threads.h \ layout.h \ + merge.h \ object.h \ options.h \ output.h \ diff --git a/gold/Makefile.in b/gold/Makefile.in index 36994c3dad9..884b1a52c88 100644 --- a/gold/Makefile.in +++ b/gold/Makefile.in @@ -71,10 +71,11 @@ libgold_a_LIBADD = am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) defstd.$(OBJEXT) \ dirsearch.$(OBJEXT) dynobj.$(OBJEXT) fileread.$(OBJEXT) \ gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \ - object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \ - readsyms.$(OBJEXT) reloc.$(OBJEXT) resolve.$(OBJEXT) \ - script.$(OBJEXT) symtab.$(OBJEXT) stringpool.$(OBJEXT) \ - target-select.$(OBJEXT) workqueue.$(OBJEXT) + merge.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \ + output.$(OBJEXT) readsyms.$(OBJEXT) reloc.$(OBJEXT) \ + resolve.$(OBJEXT) script.$(OBJEXT) symtab.$(OBJEXT) \ + stringpool.$(OBJEXT) target-select.$(OBJEXT) \ + workqueue.$(OBJEXT) am__objects_2 = am__objects_3 = yyscript.$(OBJEXT) am_libgold_a_OBJECTS = $(am__objects_1) $(am__objects_2) \ @@ -256,6 +257,7 @@ CCFILES = \ gold.cc \ gold-threads.cc \ layout.cc \ + merge.cc \ object.cc \ options.cc \ output.cc \ @@ -278,6 +280,7 @@ HFILES = \ gold.h \ gold-threads.h \ layout.h \ + merge.h \ object.h \ options.h \ output.h \ @@ -398,6 +401,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layout.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/merge.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@ diff --git a/gold/dynobj.h b/gold/dynobj.h index 476b602f30b..d63aa6af0b2 100644 --- a/gold/dynobj.h +++ b/gold/dynobj.h @@ -12,7 +12,6 @@ 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. diff --git a/gold/i386.cc b/gold/i386.cc index dbbd2c09b73..448453aa349 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -109,7 +109,7 @@ class Target_i386 : public Sized_target<32, false> relocate(const Relocate_info<32, false>*, Target_i386*, size_t relnum, const elfcpp::Rel<32, false>&, unsigned int r_type, const Sized_symbol<32>*, - elfcpp::Elf_types<32>::Elf_Addr, + const Symbol_value<32>*, unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t); @@ -119,7 +119,7 @@ class Target_i386 : public Sized_target<32, false> relocate_tls(const Relocate_info<32, false>*, size_t relnum, const elfcpp::Rel<32, false>&, unsigned int r_type, const Sized_symbol<32>*, - elfcpp::Elf_types<32>::Elf_Addr, + const Symbol_value<32>*, unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t); // Do a TLS Initial-Exec to Local-Exec transition. @@ -1027,7 +1027,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, const elfcpp::Rel<32, false>& rel, unsigned int r_type, const Sized_symbol<32>* gsym, - elfcpp::Elf_types<32>::Elf_Addr value, + const Symbol_value<32>* psymval, unsigned char* view, elfcpp::Elf_types<32>::Elf_Addr address, off_t view_size) @@ -1050,14 +1050,19 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, } // Pick the value to use for symbols defined in shared objects. + Symbol_value<32> symval; if (gsym != NULL && gsym->is_from_dynobj()) { - if (gsym->has_plt_offset()) - value = target->plt_section()->address() + gsym->plt_offset(); - else + if (!gsym->has_plt_offset()) gold_unreachable(); + + symval.set_output_value(target->plt_section()->address() + + gsym->plt_offset()); + psymval = &symval; } + const Sized_relobj<32, false>* object = relinfo->object; + switch (r_type) { case elfcpp::R_386_NONE: @@ -1066,51 +1071,57 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, break; case elfcpp::R_386_32: - Relocate_functions<32, false>::rel32(view, value); + Relocate_functions<32, false>::rel32(view, object, psymval); break; case elfcpp::R_386_PC32: - Relocate_functions<32, false>::pcrel32(view, value, address); + Relocate_functions<32, false>::pcrel32(view, object, psymval, address); break; case elfcpp::R_386_16: - Relocate_functions<32, false>::rel16(view, value); + Relocate_functions<32, false>::rel16(view, object, psymval); break; case elfcpp::R_386_PC16: - Relocate_functions<32, false>::pcrel16(view, value, address); + Relocate_functions<32, false>::pcrel16(view, object, psymval, address); break; case elfcpp::R_386_8: - Relocate_functions<32, false>::rel8(view, value); + Relocate_functions<32, false>::rel8(view, object, psymval); break; case elfcpp::R_386_PC8: - Relocate_functions<32, false>::pcrel8(view, value, address); + Relocate_functions<32, false>::pcrel8(view, object, psymval, address); break; case elfcpp::R_386_PLT32: gold_assert(gsym->has_plt_offset() || gsym->final_value_is_known(relinfo->options)); - Relocate_functions<32, false>::pcrel32(view, value, address); + Relocate_functions<32, false>::pcrel32(view, object, psymval, address); break; case elfcpp::R_386_GOT32: // Local GOT offsets not yet supported. gold_assert(gsym); gold_assert(gsym->has_got_offset()); - value = gsym->got_offset(); - Relocate_functions<32, false>::rel32(view, value); + Relocate_functions<32, false>::rel32(view, gsym->got_offset()); break; case elfcpp::R_386_GOTOFF: - value -= target->got_section(NULL, NULL, NULL)->address(); - Relocate_functions<32, false>::rel32(view, value); + { + elfcpp::Elf_types<32>::Elf_Addr value; + value = (psymval->value(object, 0) + - target->got_section(NULL, NULL, NULL)->address()); + Relocate_functions<32, false>::rel32(view, value); + } break; case elfcpp::R_386_GOTPC: - value = target->got_section(NULL, NULL, NULL)->address(); - Relocate_functions<32, false>::pcrel32(view, value, address); + { + elfcpp::Elf_types<32>::Elf_Addr value; + value = target->got_section(NULL, NULL, NULL)->address(); + Relocate_functions<32, false>::pcrel32(view, value, address); + } break; case elfcpp::R_386_COPY: @@ -1139,7 +1150,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, case elfcpp::R_386_TLS_LE_32: case elfcpp::R_386_TLS_GOTDESC: case elfcpp::R_386_TLS_DESC_CALL: - this->relocate_tls(relinfo, relnum, rel, r_type, gsym, value, view, + this->relocate_tls(relinfo, relnum, rel, r_type, gsym, psymval, view, address, view_size); break; @@ -1173,7 +1184,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, const elfcpp::Rel<32, false>& rel, unsigned int r_type, const Sized_symbol<32>* gsym, - elfcpp::Elf_types<32>::Elf_Addr value, + const Symbol_value<32>* psymval, unsigned char* view, elfcpp::Elf_types<32>::Elf_Addr, off_t view_size) @@ -1187,6 +1198,8 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, gold_exit(false); } + elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(relinfo->object, 0); + const bool is_final = (gsym == NULL ? !relinfo->options->is_shared() : gsym->final_value_is_known(relinfo->options)); diff --git a/gold/layout.cc b/gold/layout.cc index c150707819b..62ba5f30dec 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -133,7 +133,9 @@ Layout::get_output_section(const char* name, Stringpool::Key name_key, // We should ignore some flags. flags &= ~ (elfcpp::SHF_INFO_LINK | elfcpp::SHF_LINK_ORDER - | elfcpp::SHF_GROUP); + | elfcpp::SHF_GROUP + | elfcpp::SHF_MERGE + | elfcpp::SHF_STRINGS); const Key key(name_key, std::make_pair(type, flags)); const std::pair<Key, Output_section*> v(key, NULL); @@ -224,7 +226,7 @@ Output_section* Layout::make_output_section(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags) { - Output_section* os = new Output_section(name, type, flags, true); + Output_section* os = new Output_section(name, type, flags); this->section_list_.push_back(os); if ((flags & elfcpp::SHF_ALLOC) == 0) @@ -466,7 +468,6 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) off_t off = this->set_segment_offsets(target, load_seg, &shndx); // Create the symbol table sections. - // FIXME: We don't need to do this if we are stripping symbols. this->create_symtab_sections(size, input_objects, symtab, &off); // Create the .shstrtab section. @@ -690,7 +691,9 @@ Layout::set_section_offsets(off_t off, unsigned int* pshndx) return off; } -// Create the symbol table sections. +// Create the symbol table sections. Here we also set the final +// values of the symbols. At this point all the loadable sections are +// fully laid out. void Layout::create_symtab_sections(int size, const Input_objects* input_objects, diff --git a/gold/merge.cc b/gold/merge.cc new file mode 100644 index 00000000000..7af4faa03c9 --- /dev/null +++ b/gold/merge.cc @@ -0,0 +1,333 @@ +// merge.cc -- handle section merging for gold + +#include "gold.h" + +#include <cstdlib> + +#include "merge.h" + +namespace gold +{ + +// Sort the entries in a merge mapping. The key is an input object, a +// section index in that object, and an offset in that section. + +bool +Output_merge_base::Merge_key_less::operator()(const Merge_key& mk1, + const Merge_key& mk2) const +{ + // The order of different objects and different sections doesn't + // matter. We want to get consistent results across links so we + // don't use pointer comparison. + if (mk1.object != mk2.object) + return mk1.object->name() < mk2.object->name(); + if (mk1.shndx != mk2.shndx) + return mk1.shndx < mk2.shndx; + return mk1.offset < mk2.offset; +} + +// Add a mapping from an OFFSET in input section SHNDX in object +// OBJECT to an OUTPUT_OFFSET in a merged output section. This +// manages the mapping used to resolve relocations against merged +// sections. + +void +Output_merge_base::add_mapping(Relobj* object, unsigned int shndx, + off_t offset, off_t output_offset) +{ + Merge_key mk; + mk.object = object; + mk.shndx = shndx; + mk.offset = offset; + std::pair<Merge_map::iterator, bool> ins = + this->merge_map_.insert(std::make_pair(mk, output_offset)); + gold_assert(ins.second); +} + +// Return the output address for an input address. The input address +// is at offset OFFSET in section SHNDX in OBJECT. +// OUTPUT_SECTION_ADDRESS is the address of the output section. If we +// know the address, set *POUTPUT and return true. Otherwise return +// false. + +bool +Output_merge_base::do_output_address(const Relobj* object, unsigned int shndx, + off_t offset, + uint64_t output_section_address, + uint64_t* poutput) const +{ + gold_assert(output_section_address == this->address()); + + Merge_key mk; + mk.object = object; + mk.shndx = shndx; + mk.offset = offset; + Merge_map::const_iterator p = this->merge_map_.lower_bound(mk); + + // If MK is not in the map, lower_bound returns the next iterator + // larger than it. + if (p->first.object != object + || p->first.shndx != shndx + || p->first.offset != offset) + { + if (p == this->merge_map_.begin()) + return false; + --p; + } + + if (p->first.object != object || p->first.shndx != shndx) + return false; + + // Any input section is fully mapped: we don't need to know the size + // of the range starting at P->FIRST.OFFSET. + *poutput = output_section_address + p->second + (offset - p->first.offset); + return true; +} + +// Compute the hash code for a fixed-size constant. + +size_t +Output_merge_data::Merge_data_hash::operator()(Merge_data_key k) const +{ + const unsigned char* p = this->pomd_->constant(k); + uint64_t entsize = this->pomd_->entsize(); + + // Fowler/Noll/Vo (FNV) hash (type FNV-1a). + if (sizeof(size_t) == 8) + { + size_t result = static_cast<size_t>(14695981039346656037ULL); + for (uint64_t i = 0; i < entsize; ++i) + { + result &= (size_t) *p++; + result *= 1099511628211ULL; + } + return result; + } + else + { + size_t result = 2166136261UL; + for (uint64_t i = 0; i < entsize; ++i) + { + result ^= (size_t) *p++; + result *= 16777619UL; + } + return result; + } +} + +// Return whether one hash table key equals another. + +bool +Output_merge_data::Merge_data_eq::operator()(Merge_data_key k1, + Merge_data_key k2) const +{ + const unsigned char* p1 = this->pomd_->constant(k1); + const unsigned char* p2 = this->pomd_->constant(k2); + return memcmp(p1, p2, this->pomd_->entsize()) == 0; +} + +// Add a constant to the end of the section contents. + +void +Output_merge_data::add_constant(const unsigned char* p) +{ + uint64_t entsize = this->entsize(); + if (this->len_ + entsize > this->alc_) + { + if (this->alc_ == 0) + this->alc_ = 128 * entsize; + else + this->alc_ *= 2; + this->p_ = static_cast<unsigned char*>(realloc(this->p_, this->alc_)); + if (this->p_ == NULL) + gold_fatal("out of memory", true); + } + + memcpy(this->p_ + this->len_, p, entsize); + this->len_ += entsize; +} + +// Add the input section SHNDX in OBJECT to a merged output section +// which holds fixed length constants. Return whether we were able to +// handle the section; if not, it will be linked as usual without +// constant merging. + +bool +Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx) +{ + off_t len; + const unsigned char* p = object->section_contents(shndx, &len); + + uint64_t entsize = this->entsize(); + + if (len % entsize != 0) + return false; + + for (off_t i = 0; i < len; i += entsize, p += entsize) + { + // Add the constant to the section contents. If we find that it + // is already in the hash table, we will remove it again. + Merge_data_key k = this->len_; + this->add_constant(p); + + std::pair<Merge_data_hashtable::iterator, bool> ins = + this->hashtable_.insert(k); + + if (!ins.second) + { + // Key was already present. Remove the copy we just added. + this->len_ -= entsize; + k = *ins.first; + } + + // Record the offset of this constant in the output section. + this->add_mapping(object, shndx, i, k); + } + + return true; +} + +// Set the final data size in a merged output section with fixed size +// constants. + +void +Output_merge_data::do_set_address(uint64_t, off_t) +{ + // Release the memory we don't need. + this->p_ = static_cast<unsigned char*>(realloc(this->p_, this->len_)); + gold_assert(this->p_ != NULL); + this->set_data_size(this->len_); +} + +// Write the data of a merged output section with fixed size constants +// to the file. + +void +Output_merge_data::do_write(Output_file* of) +{ + of->write(this->offset(), this->p_, this->len_); +} + +// Compute a hash code for a Merge_string_key, which is an object, a +// section index, and an offset. + +template<typename Char_type> +size_t +Output_merge_string<Char_type>::Merge_string_key_hash::operator()( + const Merge_string_key& key) const +{ + // This is a very simple minded hash code. Fix it if it we get too + // many collisions. + const std::string& oname(key.object->name()); + return oname[0] + oname.length() + key.shndx + key.offset; +} + +// Compare two Merge_string_keys for equality. + +template<typename Char_type> +bool +Output_merge_string<Char_type>::Merge_string_key_eq::operator()( + const Merge_string_key& k1, const Merge_string_key& k2) const +{ + return (k1.object == k2.object + && k1.shndx == k2.shndx + && k1.offset == k2.offset); +} + +// Add an input section to a merged string section. + +template<typename Char_type> +bool +Output_merge_string<Char_type>::do_add_input_section(Relobj* object, + unsigned int shndx) +{ + off_t len; + const unsigned char* pdata = object->section_contents(shndx, &len); + + const Char_type* p = reinterpret_cast<const Char_type*>(pdata); + + if (len % sizeof(Char_type) != 0) + { + fprintf(stderr, + _("%s: %s: mergeable string section length not multiple of " + "character size\n"), + program_name, object->name().c_str()); + gold_exit(false); + } + len /= sizeof(Char_type); + + off_t i = 0; + while (i < len) + { + off_t plen = 0; + for (const Char_type* pl = p; *pl != 0; ++pl) + { + ++plen; + if (i + plen >= len) + { + fprintf(stderr, + _("%s: %s: entry in mergeable string section " + "not null terminated\n"), + program_name, object->name().c_str()); + gold_exit(false); + } + } + + const Char_type* str = this->stringpool_.add(p, NULL); + + Merge_string_key k(object, shndx, i); + typename Merge_string_hashtable::value_type v(k, str); + bool b = this->hashtable_.insert(v).second; + gold_assert(b); + + p += plen + 1; + i += plen + 1; + } + + return true; +} + +// Set the final data size of a merged string section. This is where +// we finalize the mappings from the input sections to the output +// section. + +template<typename Char_type> +void +Output_merge_string<Char_type>::do_set_address(uint64_t, off_t) +{ + this->stringpool_.set_string_offsets(); + + for (typename Merge_string_hashtable::const_iterator p = + this->hashtable_.begin(); + p != this->hashtable_.end(); + ++p) + this->add_mapping(p->first.object, p->first.shndx, p->first.offset, + this->stringpool_.get_offset(p->second)); + + this->set_data_size(this->stringpool_.get_strtab_size()); + + // Save some memory. + this->hashtable_.clear(); +} + +// Write out a merged string section. + +template<typename Char_type> +void +Output_merge_string<Char_type>::do_write(Output_file* of) +{ + this->stringpool_.write(of, this->offset()); +} + +// Instantiate the templates we need. + +template +class Output_merge_string<char>; + +template +class Output_merge_string<uint16_t>; + +template +class Output_merge_string<uint32_t>; + +} // End namespace gold. diff --git a/gold/merge.h b/gold/merge.h new file mode 100644 index 00000000000..dd97bf2d39e --- /dev/null +++ b/gold/merge.h @@ -0,0 +1,226 @@ +// merge.h -- handle section merging for gold -*- C++ -*- + +#ifndef GOLD_MERGE_H +#define GOLD_MERGE_H + +#include <climits> + +#include "stringpool.h" +#include "output.h" + +namespace gold +{ + +// A general class for SHF_MERGE data, to hold functions shared by +// fixed-size constant data and string data. + +class Output_merge_base : public Output_section_data +{ + public: + Output_merge_base(uint64_t entsize) + : Output_section_data(1), merge_map_(), entsize_(entsize) + { } + + // Return the output address for an input address. + bool + do_output_address(const Relobj* object, unsigned int shndx, off_t offset, + uint64_t output_section_address, uint64_t* poutput) const; + + protected: + // Return the entry size. + uint64_t + entsize() const + { return this->entsize_; } + + // Add a mapping from an OFFSET in input section SHNDX in object + // OBJECT to an OUTPUT_OFFSET in the output section. + void + add_mapping(Relobj* object, unsigned int shndx, off_t offset, + off_t output_offset); + + private: + // We build a mapping from OBJECT/SHNDX/OFFSET to an offset in the + // output section. + struct Merge_key + { + const Relobj* object; + unsigned int shndx; + off_t offset; + }; + + struct Merge_key_less + { + bool + operator()(const Merge_key&, const Merge_key&) const; + }; + + typedef std::map<Merge_key, off_t, Merge_key_less> Merge_map; + + // A mapping from input object/section/offset to offset in output + // section. + Merge_map merge_map_; + + // The entry size. For fixed-size constants, this is the size of + // the constants. For strings, this is the size of a character. + uint64_t entsize_; +}; + +// Handle SHF_MERGE sections with fixed-size constant data. + +class Output_merge_data : public Output_merge_base +{ + public: + Output_merge_data(uint64_t entsize) + : Output_merge_base(entsize), p_(NULL), len_(0), alc_(0), + hashtable_(128, Merge_data_hash(this), Merge_data_eq(this)) + { } + + // Add an input section. + bool + do_add_input_section(Relobj* object, unsigned int shndx); + + // Set the final data size. + void + do_set_address(uint64_t, off_t); + + // Write the data to the file. + void + do_write(Output_file*); + + private: + // We build a hash table of the fixed-size constants. Each constant + // is stored as a pointer into the section data we are accumulating. + + // A key in the hash table. This is an offset in the section + // contents we are building. + typedef off_t Merge_data_key; + + // Compute the hash code. To do this we need a pointer back to the + // object holding the data. + class Merge_data_hash + { + public: + Merge_data_hash(const Output_merge_data* pomd) + : pomd_(pomd) + { } + + size_t + operator()(Merge_data_key) const; + + private: + const Output_merge_data* pomd_; + }; + + friend class Merge_data_hash; + + // Compare two entries in the hash table for equality. To do this + // we need a pointer back to the object holding the data. Note that + // we now have a pointer to the object stored in two places in the + // hash table. Fixing this would require specializing the hash + // table, which would be hard to do portably. + class Merge_data_eq + { + public: + Merge_data_eq(const Output_merge_data* pomd) + : pomd_(pomd) + { } + + bool + operator()(Merge_data_key k1, Merge_data_key k2) const; + + private: + const Output_merge_data* pomd_; + }; + + friend class Merge_data_eq; + + // The type of the hash table. + typedef Unordered_set<Merge_data_key, Merge_data_hash, Merge_data_eq> + Merge_data_hashtable; + + // Given a hash table key, which is just an offset into the section + // data, return a pointer to the corresponding constant. + const unsigned char* + constant(Merge_data_key k) const + { + gold_assert(k >= 0 && k < this->len_); + return this->p_ + k; + } + + // Add a constant to the output. + void + add_constant(const unsigned char*); + + // The accumulated data. + unsigned char* p_; + // The length of the accumulated data. + off_t len_; + // The size of the allocated buffer. + size_t alc_; + // The hash table. + Merge_data_hashtable hashtable_; +}; + +// Handle SHF_MERGE sections with string data. This is a template +// based on the type of the characters in the string. + +template<typename Char_type> +class Output_merge_string : public Output_merge_base +{ + public: + Output_merge_string() + : Output_merge_base(sizeof(Char_type)), stringpool_(false), hashtable_() + { } + + // Add an input section. + bool + do_add_input_section(Relobj* object, unsigned int shndx); + + // Set the final data size. + void + do_set_address(uint64_t, off_t); + + // Write the data to the file. + void + do_write(Output_file*); + + private: + // As we see input sections, we build a mapping from object, section + // index and offset to strings. + struct Merge_string_key + { + Relobj* object; + unsigned int shndx; + off_t offset; + + Merge_string_key(Relobj *objecta, unsigned int shndxa, off_t offseta) + : object(objecta), shndx(shndxa), offset(offseta) + { } + }; + + struct Merge_string_key_hash + { + size_t + operator()(const Merge_string_key&) const; + }; + + struct Merge_string_key_eq + { + bool + operator()(const Merge_string_key&, const Merge_string_key&) const; + }; + + typedef Unordered_map<Merge_string_key, const Char_type*, + Merge_string_key_hash, Merge_string_key_eq> + Merge_string_hashtable; + + // As we see the strings, we add them to a Stringpool. + Stringpool_template<Char_type> stringpool_; + // Map from a location in an input object to an entry in the + // Stringpool. + Merge_string_hashtable hashtable_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_MERGE_H) diff --git a/gold/object.cc b/gold/object.cc index 01c4c1625ce..eb975c6c734 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -127,8 +127,7 @@ Sized_relobj<size, big_endian>::Sized_relobj( output_local_symbol_count_(0), symbols_(NULL), local_symbol_offset_(0), - local_values_(), - local_indexes_() + local_values_() { } @@ -505,10 +504,9 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab, // Finalize the local symbols. Here we record the file offset at // which they should be output, we add their names to *POOL, and we -// add their values to THIS->LOCAL_VALUES_ and their indexes in the -// output symbol table to THIS->LOCAL_INDEXES_. Return the symbol -// index. This function is always called from the main thread. The -// actual output of the local symbols will occur in a separate task. +// add their values to THIS->LOCAL_VALUES_. Return the symbol index. +// This function is always called from the main thread. The actual +// output of the local symbols will occur in a separate task. template<int size, bool big_endian> unsigned int @@ -542,7 +540,6 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index, locsize); this->local_values_.resize(loccount); - this->local_indexes_.resize(loccount); // Read the symbol names. const unsigned int strtab_shndx = symtabshdr.get_sh_link(); @@ -562,12 +559,15 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index, { elfcpp::Sym<size, big_endian> sym(psyms); + Symbol_value<size>& lv(this->local_values_[i]); + unsigned int shndx = sym.get_st_shndx(); + lv.set_input_shndx(shndx); if (shndx >= elfcpp::SHN_LORESERVE) { if (shndx == elfcpp::SHN_ABS) - this->local_values_[i] = sym.get_st_value(); + lv.set_output_value(sym.get_st_value()); else { // FIXME: Handle SHN_XINDEX. @@ -589,23 +589,28 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index, gold_exit(false); } - if (mo[shndx].output_section == NULL) + Output_section* os = mo[shndx].output_section; + + if (os == NULL) { - this->local_values_[i] = 0; - this->local_indexes_[i] = -1U; + lv.set_output_value(0); + lv.set_no_output_symtab_entry(); continue; } - this->local_values_[i] = (mo[shndx].output_section->address() - + mo[shndx].offset - + sym.get_st_value()); + if (mo[shndx].offset == -1) + lv.set_input_value(sym.get_st_value()); + else + lv.set_output_value(mo[shndx].output_section->address() + + mo[shndx].offset + + sym.get_st_value()); } // Decide whether this symbol should go into the output file. if (sym.get_st_type() == elfcpp::STT_SECTION) { - this->local_indexes_[i] = -1U; + lv.set_no_output_symtab_entry(); continue; } @@ -622,9 +627,8 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index, const char* name = pnames + sym.get_st_name(); pool->add(name, NULL); - this->local_indexes_[i] = index; + lv.set_output_symtab_index(index); ++index; - off += sym_size; ++count; } @@ -633,6 +637,23 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index, return index; } +// Return the value of a local symbol defined in input section SHNDX, +// with value VALUE, adding addend ADDEND. This handles SHF_MERGE +// sections. +template<int size, bool big_endian> +typename elfcpp::Elf_types<size>::Elf_Addr +Sized_relobj<size, big_endian>::local_value(unsigned int shndx, + Address value, + Address addend) const +{ + const std::vector<Map_to_output>& mo(this->map_to_output()); + Output_section* os = mo[shndx].output_section; + if (os == NULL) + return addend; + gold_assert(mo[shndx].offset == -1); + return os->output_address(this, shndx, value + addend); +} + // Write out the local symbols. template<int size, bool big_endian> @@ -676,7 +697,6 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of, const std::vector<Map_to_output>& mo(this->map_to_output()); gold_assert(this->local_values_.size() == loccount); - gold_assert(this->local_indexes_.size() == loccount); unsigned char* ov = oview; psyms += sym_size; @@ -684,9 +704,8 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of, { elfcpp::Sym<size, big_endian> isym(psyms); - if (this->local_indexes_[i] == -1U) + if (!this->local_values_[i].needs_output_symtab_entry()) continue; - gold_assert(this->local_indexes_[i] != 0); unsigned int st_shndx = isym.get_st_shndx(); if (st_shndx < elfcpp::SHN_LORESERVE) @@ -702,7 +721,7 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of, gold_assert(isym.get_st_name() < strtab_size); const char* name = pnames + isym.get_st_name(); osym.put_st_name(sympool->get_offset(name)); - osym.put_st_value(this->local_values_[i]); + osym.put_st_value(this->local_values_[i].value(this, 0)); osym.put_st_size(isym.get_st_size()); osym.put_st_info(isym.get_st_info()); osym.put_st_other(isym.get_st_other()); diff --git a/gold/object.h b/gold/object.h index 2df04abad85..2027f8e97df 100644 --- a/gold/object.h +++ b/gold/object.h @@ -15,12 +15,14 @@ namespace gold { class General_options; -class Stringpool; class Layout; class Output_section; class Output_file; class Dynobj; +template<typename Stringpool_char> +class Stringpool_template; + // Data to pass from read_symbols() to add_symbols(). struct Read_symbols_data @@ -338,7 +340,7 @@ Object::sized_target(ACCEPT_SIZE_ENDIAN_ONLY) } // A regular object (ET_REL). This is an abstract base class itself. -// The implementations is the template class Sized_relobj. +// The implementation is the template class Sized_relobj. class Relobj : public Object { @@ -362,7 +364,8 @@ class Relobj : public Object // symbol information will be stored; add local symbol names to // *POOL; return the new local symbol index. unsigned int - finalize_local_symbols(unsigned int index, off_t off, Stringpool* pool) + finalize_local_symbols(unsigned int index, off_t off, + Stringpool_template<char>* pool) { return this->do_finalize_local_symbols(index, off, pool); } // Relocate the input sections and write out the local symbols. @@ -383,7 +386,7 @@ class Relobj : public Object // (which will be NULL if the section is not included in the link) // and set *POFF to the offset within that section. inline Output_section* - output_section(unsigned int shndx, off_t* poff); + output_section(unsigned int shndx, off_t* poff) const; // Set the offset of an input section within its output section. void @@ -402,7 +405,8 @@ class Relobj : public Object // The output section. This is NULL if the input section is to be // discarded. Output_section* output_section; - // The offset within the output section. + // The offset within the output section. This is -1 if the + // section requires special handling. off_t offset; }; @@ -417,7 +421,8 @@ class Relobj : public Object // Finalize local symbols--implemented by child class. virtual unsigned int - do_finalize_local_symbols(unsigned int, off_t, Stringpool*) = 0; + do_finalize_local_symbols(unsigned int, off_t, + Stringpool_template<char>*) = 0; // Relocate the input sections and write out the local // symbols--implemented by child class. @@ -430,6 +435,10 @@ class Relobj : public Object map_to_output() { return this->map_to_output_; } + const std::vector<Map_to_output>& + map_to_output() const + { return this->map_to_output_; } + private: // Mapping from input sections to output section. std::vector<Map_to_output> map_to_output_; @@ -437,7 +446,7 @@ class Relobj : public Object // Implement Object::output_section inline for efficiency. inline Output_section* -Relobj::output_section(unsigned int shndx, off_t* poff) +Relobj::output_section(unsigned int shndx, off_t* poff) const { gold_assert(shndx < this->map_to_output_.size()); const Map_to_output& mo(this->map_to_output_[shndx]); @@ -445,6 +454,108 @@ Relobj::output_section(unsigned int shndx, off_t* poff) return mo.output_section; } +// This POD class is holds the value of a symbol. This is used for +// local symbols, and for all symbols during relocation processing. +// In order to process relocs we need to be able to handle SHF_MERGE +// sections correctly. + +template<int size> +class Symbol_value +{ + public: + typedef typename elfcpp::Elf_types<size>::Elf_Addr Value; + + Symbol_value() + : output_symtab_index_(0), input_shndx_(0), needs_output_address_(false), + value_(0) + { } + + // Get the value of this symbol. OBJECT is the object in which this + // symbol is defined, and ADDEND is an addend to add to the value. + template<bool big_endian> + Value + value(const Sized_relobj<size, big_endian>* object, Value addend) const + { + if (!this->needs_output_address_) + return this->value_ + addend; + return object->local_value(this->input_shndx_, this->value_, addend); + } + + // Set the value of this symbol in the output symbol table. + void + set_output_value(Value value) + { + this->value_ = value; + this->needs_output_address_ = false; + } + + // If this symbol is mapped to an output section which requires + // special handling to determine the output value, we store the + // value of the symbol in the input file. This is used for + // SHF_MERGE sections. + void + set_input_value(Value value) + { + this->value_ = value; + this->needs_output_address_ = true; + } + + // Return whether this symbol should go into the output symbol + // table. + bool + needs_output_symtab_entry() const + { + gold_assert(this->output_symtab_index_ != 0); + return this->output_symtab_index_ != -1U; + } + + // Return the index in the output symbol table. + unsigned int + output_symtab_index() const + { + gold_assert(this->output_symtab_index_ != 0); + return this->output_symtab_index_; + } + + // Set the index in the output symbol table. + void + set_output_symtab_index(unsigned int i) + { + gold_assert(this->output_symtab_index_ == 0); + this->output_symtab_index_ = i; + } + + // Record that this symbol should not go into the output symbol + // table. + void + set_no_output_symtab_entry() + { + gold_assert(this->output_symtab_index_ == 0); + this->output_symtab_index_ = -1U; + } + + // Set the index of the input section in the input file. + void + set_input_shndx(unsigned int i) + { this->input_shndx_ = i; } + + private: + // The index of this local symbol in the output symbol table. This + // will be -1 if the symbol should not go into the symbol table. + unsigned int output_symtab_index_; + // The section index in the input file in which this symbol is + // defined. + unsigned int input_shndx_ : 31; + // Whether getting the value of this symbol requires calling an + // Output_section method. For example, this will be true of a + // STT_SECTION symbol in a SHF_MERGE section. + bool needs_output_address_ : 1; + // The value of the symbol. If !needs_output_address_, this is the + // value in the output file. If needs_output_address_, this is the + // value in the input file. + Value value_; +}; + // A regular object file. This is size and endian specific. template<int size, bool big_endian> @@ -452,7 +563,7 @@ class Sized_relobj : public Relobj { public: typedef typename elfcpp::Elf_types<size>::Elf_Addr Address; - typedef std::vector<Address> Local_values; + typedef std::vector<Symbol_value<size> > Local_values; Sized_relobj(const std::string& name, Input_file* input_file, off_t offset, const typename elfcpp::Ehdr<size, big_endian>&); @@ -468,9 +579,8 @@ class Sized_relobj : public Relobj unsigned int symtab_index(unsigned int sym) const { - gold_assert(sym < this->local_indexes_.size()); - gold_assert(this->local_indexes_[sym] != 0); - return this->local_indexes_[sym]; + gold_assert(sym < this->local_values_.size()); + return this->local_values_[sym].output_symtab_index(); } // Read the symbols. @@ -497,7 +607,8 @@ class Sized_relobj : public Relobj // Finalize the local symbols. unsigned int - do_finalize_local_symbols(unsigned int, off_t, Stringpool*); + do_finalize_local_symbols(unsigned int, off_t, + Stringpool_template<char>*); // Relocate the input sections and write out the local symbols. void @@ -528,6 +639,12 @@ class Sized_relobj : public Relobj SELECT_SIZE_ENDIAN_ONLY(size, big_endian)); } + // Return the value of a local symbol define in input section SHNDX, + // with value VALUE, adding addend ADDEND. This handles SHF_MERGE + // sections. + Address + local_value(unsigned int shndx, Address value, Address addend) const; + private: // For convenience. typedef Sized_relobj<size, big_endian> This; @@ -574,7 +691,8 @@ class Sized_relobj : public Relobj // Write out the local symbols. void - write_local_symbols(Output_file*, const Stringpool*); + write_local_symbols(Output_file*, + const Stringpool_template<char>*); // General access to the ELF file. elfcpp::Elf_file<size, big_endian, Object> elf_file_; @@ -590,8 +708,6 @@ class Sized_relobj : public Relobj off_t local_symbol_offset_; // Values of local symbols. Local_values local_values_; - // Indexes of local symbols in the output file; -1U if not present. - std::vector<unsigned int> local_indexes_; }; // A class to manage the list of all objects. diff --git a/gold/output.cc b/gold/output.cc index f0d7985732d..2a7400def77 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -12,6 +12,7 @@ #include "object.h" #include "symtab.h" #include "reloc.h" +#include "merge.h" #include "output.h" namespace gold @@ -790,9 +791,9 @@ off_t Output_section::Input_section::data_size() const { if (this->is_input_section()) - return this->data_size_; + return this->u1_.data_size; else - return this->u_.posd->data_size(); + return this->u2_.posd->data_size(); } // Set the address and file offset. @@ -802,9 +803,33 @@ Output_section::Input_section::set_address(uint64_t addr, off_t off, off_t secoff) { if (this->is_input_section()) - this->u_.object->set_section_offset(this->shndx_, off - secoff); + this->u2_.object->set_section_offset(this->shndx_, off - secoff); else - this->u_.posd->set_address(addr, off); + this->u2_.posd->set_address(addr, off); +} + +// Try to turn an input address into an output address. + +bool +Output_section::Input_section::output_address(const Relobj* object, + unsigned int shndx, + off_t offset, + uint64_t output_section_address, + uint64_t *poutput) const +{ + if (!this->is_input_section()) + return this->u2_.posd->output_address(object, shndx, offset, + output_section_address, poutput); + else + { + if (this->u2_.object != object) + return false; + off_t output_offset; + Output_section* os = object->output_section(shndx, &output_offset); + gold_assert(os != NULL); + *poutput = output_section_address + output_offset + offset; + return true; + } } // Write out the data. We don't have to do anything for an input @@ -815,7 +840,7 @@ void Output_section::Input_section::write(Output_file* of) { if (!this->is_input_section()) - this->u_.posd->write(of); + this->u2_.posd->write(of); } // Output_section methods. @@ -823,7 +848,7 @@ Output_section::Input_section::write(Output_file* of) // Construct an Output_section. NAME will point into a Stringpool. Output_section::Output_section(const char* name, elfcpp::Elf_Word type, - elfcpp::Elf_Xword flags, bool may_add_data) + elfcpp::Elf_Xword flags) : name_(name), addralign_(0), entsize_(0), @@ -838,7 +863,6 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, dynsym_index_(0), input_sections_(), first_input_offset_(0), - may_add_data_(may_add_data), needs_symtab_index_(false), needs_dynsym_index_(false), should_link_to_symtab_(false), @@ -873,8 +897,6 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx, const char* secname, const elfcpp::Shdr<size, big_endian>& shdr) { - gold_assert(this->may_add_data_); - elfcpp::Elf_Xword addralign = shdr.get_sh_addralign(); if ((addralign & (addralign - 1)) != 0) { @@ -887,6 +909,20 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx, if (addralign > this->addralign_) this->addralign_ = addralign; + // If this is a SHF_MERGE section, we pass all the input sections to + // a Output_data_merge. + if ((shdr.get_sh_flags() & elfcpp::SHF_MERGE) != 0) + { + if (this->add_merge_input_section(object, shndx, shdr.get_sh_flags(), + shdr.get_sh_entsize(), + addralign)) + { + // Tell the relocation routines that they need to call the + // output_address method to determine the final address. + return -1; + } + } + off_t ssize = this->data_size(); ssize = align_address(ssize, addralign); this->set_data_size(ssize + shdr.get_sh_size()); @@ -907,18 +943,107 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx, void Output_section::add_output_section_data(Output_section_data* posd) { - gold_assert(this->may_add_data_); + Input_section inp(posd); + this->add_output_section_data(&inp); +} + +// Add arbitrary data to an output section by Input_section. +void +Output_section::add_output_section_data(Input_section* inp) +{ if (this->input_sections_.empty()) this->first_input_offset_ = this->data_size(); - this->input_sections_.push_back(Input_section(posd)); + this->input_sections_.push_back(*inp); - uint64_t addralign = posd->addralign(); + uint64_t addralign = inp->addralign(); if (addralign > this->addralign_) this->addralign_ = addralign; - posd->set_output_section(this); + inp->set_output_section(this); +} + +// Add a merge section to an output section. + +void +Output_section::add_output_merge_section(Output_section_data* posd, + bool is_string, uint64_t entsize) +{ + Input_section inp(posd, is_string, entsize); + this->add_output_section_data(&inp); +} + +// Add an input section to a SHF_MERGE section. + +bool +Output_section::add_merge_input_section(Relobj* object, unsigned int shndx, + uint64_t flags, uint64_t entsize, + uint64_t addralign) +{ + // We only merge constants if the alignment is not more than the + // entry size. This could be handled, but it's unusual. + if (addralign > entsize) + return false; + + bool is_string = (flags & elfcpp::SHF_STRINGS) != 0; + Input_section_list::iterator p; + for (p = this->input_sections_.begin(); + p != this->input_sections_.end(); + ++p) + if (p->is_merge_section(is_string, entsize)) + break; + + // We handle the actual constant merging in Output_merge_data or + // Output_merge_string_data. + if (p != this->input_sections_.end()) + p->add_input_section(object, shndx); + else + { + Output_section_data* posd; + if (!is_string) + posd = new Output_merge_data(entsize); + else if (entsize == 1) + posd = new Output_merge_string<char>(); + else if (entsize == 2) + posd = new Output_merge_string<uint16_t>(); + else if (entsize == 4) + posd = new Output_merge_string<uint32_t>(); + else + return false; + + this->add_output_merge_section(posd, is_string, entsize); + posd->add_input_section(object, shndx); + } + + return true; +} + +// Return the output virtual address of OFFSET relative to the start +// of input section SHNDX in object OBJECT. + +uint64_t +Output_section::output_address(const Relobj* object, unsigned int shndx, + off_t offset) const +{ + uint64_t addr = this->address() + this->first_input_offset_; + for (Input_section_list::const_iterator p = this->input_sections_.begin(); + p != this->input_sections_.end(); + ++p) + { + addr = align_address(addr, p->addralign()); + uint64_t output; + if (p->output_address(object, shndx, offset, addr, &output)) + return output; + addr += p->data_size(); + } + + // If we get here, it means that we don't know the mapping for this + // input section. This might happen in principle if + // add_input_section were called before add_output_section_data. + // But it should never actually happen. + + gold_unreachable(); } // Set the address of an Output_section. This is where we handle @@ -1189,7 +1314,8 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff, return ret; } -// Set the addresses in a list of Output_data structures. +// Set the addresses and file offsets in a list of Output_data +// structures. uint64_t Output_segment::set_section_list_addresses(Output_data_list* pdl, @@ -1541,3 +1667,4 @@ template class Output_data_got<64, true>; } // End namespace gold. + diff --git a/gold/output.h b/gold/output.h index 013a19f1b91..7ed53ff06d7 100644 --- a/gold/output.h +++ b/gold/output.h @@ -314,6 +314,26 @@ class Output_section_data : public Output_data void set_output_section(Output_section* os); + // Add an input section, for SHF_MERGE sections. This returns true + // if the section was handled. + bool + add_input_section(Relobj* object, unsigned int shndx) + { return this->do_add_input_section(object, shndx); } + + // Given an input OBJECT, an input section index SHNDX within that + // object, and an OFFSET relative to the start of that input + // section, return whether or not the output address is known. + // OUTPUT_SECTION_ADDRESS is the address of the output section which + // this is a part of. If this function returns true, it sets + // *POUTPUT to the output address. + virtual bool + output_address(const Relobj* object, unsigned int shndx, off_t offset, + uint64_t output_section_address, uint64_t *poutput) const + { + return this->do_output_address(object, shndx, offset, + output_section_address, poutput); + } + protected: // The child class must implement do_write. @@ -323,6 +343,18 @@ class Output_section_data : public Output_data do_adjust_output_section(Output_section*) { } + // May be implemented by child class. Return true if the section + // was handled. + virtual bool + do_add_input_section(Relobj*, unsigned int) + { gold_unreachable(); } + + // The child class may implement output_address. + virtual bool + do_output_address(const Relobj*, unsigned int, off_t, uint64_t, + uint64_t*) const + { return false; } + // Return the required alignment. uint64_t do_addralign() const @@ -1114,8 +1146,7 @@ class Output_section : public Output_data { public: // Create an output section, giving the name, type, and flags. - Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword, - bool may_add_data); + Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword); virtual ~Output_section(); // Add a new input section SHNDX, named NAME, with header SHDR, from @@ -1125,7 +1156,7 @@ class Output_section : public Output_data add_input_section(Relobj* object, unsigned int shndx, const char *name, const elfcpp::Shdr<size, big_endian>& shdr); - // Add generated data ODATA to this output section. + // Add generated data POSD to this output section. void add_output_section_data(Output_section_data* posd); @@ -1284,6 +1315,12 @@ class Output_section : public Output_data this->dynsym_index_ = index; } + // Return the output virtual address of OFFSET relative to the start + // of input section SHNDX in object OBJECT. + uint64_t + output_address(const Relobj* object, unsigned int shndx, + off_t offset) const; + // Set the address of the Output_section. For a typical // Output_section, there is nothing to do, but if there are any // Output_section_data objects we need to set the final addresses @@ -1339,24 +1376,44 @@ class Output_section : public Output_data { public: Input_section() - : shndx_(0), p2align_(0), data_size_(0) - { this->u_.object = NULL; } + : shndx_(0), p2align_(0) + { + this->u1_.data_size = 0; + this->u2_.object = NULL; + } + // For an ordinary input section. Input_section(Relobj* object, unsigned int shndx, off_t data_size, uint64_t addralign) : shndx_(shndx), - p2align_(ffsll(static_cast<long long>(addralign))), - data_size_(data_size) + p2align_(ffsll(static_cast<long long>(addralign))) { - gold_assert(shndx != -1U); - this->u_.object = object; + gold_assert(shndx != OUTPUT_SECTION_CODE + && shndx != MERGE_DATA_SECTION_CODE + && shndx != MERGE_STRING_SECTION_CODE); + this->u1_.data_size = data_size; + this->u2_.object = object; } + // For a non-merge output section. Input_section(Output_section_data* posd) - : shndx_(-1U), - p2align_(ffsll(static_cast<long long>(posd->addralign()))), - data_size_(0) - { this->u_.posd = posd; } + : shndx_(OUTPUT_SECTION_CODE), + p2align_(ffsll(static_cast<long long>(posd->addralign()))) + { + this->u1_.data_size = 0; + this->u2_.posd = posd; + } + + // For a merge section. + Input_section(Output_section_data* posd, bool is_string, uint64_t entsize) + : shndx_(is_string + ? MERGE_STRING_SECTION_CODE + : MERGE_DATA_SECTION_CODE), + p2align_(ffsll(static_cast<long long>(posd->addralign()))) + { + this->u1_.entsize = entsize; + this->u2_.posd = posd; + } // The required alignment. uint64_t @@ -1371,41 +1428,125 @@ class Output_section : public Output_data off_t data_size() const; + // Return whether this is a merge section which matches the + // parameters. + bool + is_merge_section(bool is_string, uint64_t entsize) const + { + return (this->shndx_ == (is_string + ? MERGE_STRING_SECTION_CODE + : MERGE_DATA_SECTION_CODE) + && this->u1_.entsize == entsize); + } + + // Set the output section. + void + set_output_section(Output_section* os) + { + gold_assert(!this->is_input_section()); + this->u2_.posd->set_output_section(os); + } + // Set the address and file offset. This is called during // Layout::finalize. SECOFF is the file offset of the enclosing // section. void set_address(uint64_t addr, off_t off, off_t secoff); + // Add an input section, for SHF_MERGE sections. + bool + add_input_section(Relobj* object, unsigned int shndx) + { + gold_assert(this->shndx_ == MERGE_DATA_SECTION_CODE + || this->shndx_ == MERGE_STRING_SECTION_CODE); + return this->u2_.posd->add_input_section(object, shndx); + } + + // Given an input OBJECT, an input section index SHNDX within that + // object, and an OFFSET relative to the start of that input + // section, return whether or not the output address is known. + // OUTPUT_SECTION_ADDRESS is the address of the output section + // which this is a part of. If this function returns true, it + // sets *POUTPUT to the output address. + bool + output_address(const Relobj* object, unsigned int shndx, off_t offset, + uint64_t output_section_address, uint64_t *poutput) const; + // Write out the data. This does nothing for an input section. void write(Output_file*); private: + // Code values which appear in shndx_. If the value is not one of + // these codes, it is the input section index in the object file. + enum + { + // An Output_section_data. + OUTPUT_SECTION_CODE = -1U, + // An Output_section_data for an SHF_MERGE section with + // SHF_STRINGS not set. + MERGE_DATA_SECTION_CODE = -2U, + // An Output_section_data for an SHF_MERGE section with + // SHF_STRINGS set. + MERGE_STRING_SECTION_CODE = -3U + }; + // Whether this is an input section. bool is_input_section() const - { return this->shndx_ != -1U; } + { + return (this->shndx_ != OUTPUT_SECTION_CODE + && this->shndx_ != MERGE_DATA_SECTION_CODE + && this->shndx_ != MERGE_STRING_SECTION_CODE); + } - // For an ordinary input section, this is the section index in - // the input file. For an Output_section_data, this is -1U. + // For an ordinary input section, this is the section index in the + // input file. For an Output_section_data, this is + // OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or + // MERGE_STRING_SECTION_CODE. unsigned int shndx_; // The required alignment, stored as a power of 2. unsigned int p2align_; - // For an ordinary input section, the section size. - off_t data_size_; union { - // If shndx_ != -1U, this points to the object which holds the + // For an ordinary input section, the section size. + off_t data_size; + // For OUTPUT_SECTION_CODE, this is not used. For + // MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the + // entity size. + uint64_t entsize; + } u1_; + union + { + // For an ordinary input section, the object which holds the // input section. Relobj* object; - // If shndx_ == -1U, this is the data to write out. + // For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or + // MERGE_STRING_SECTION_CODE, the data. Output_section_data* posd; - } u_; + } u2_; }; typedef std::vector<Input_section> Input_section_list; + // Add a new output section by Input_section. + void + add_output_section_data(Input_section*); + + // Add an SHF_MERGE input section. Returns true if the section was + // handled. + bool + add_merge_input_section(Relobj* object, unsigned int shndx, uint64_t flags, + uint64_t entsize, uint64_t addralign); + + // Add an output SHF_MERGE section POSD to this output section. + // IS_STRING indicates whether it is a SHF_STRINGS section, and + // ENTSIZE is the entity size. This returns the entry added to + // input_sections_. + void + add_output_merge_section(Output_section_data* posd, bool is_string, + uint64_t entsize); + // Most of these fields are only valid after layout. // The name of the section. This will point into a Stringpool. @@ -1445,8 +1586,6 @@ class Output_section : public Output_data Input_section_list input_sections_; // The offset of the first entry in input_sections_. off_t first_input_offset_; - // Whether we permit adding data. - bool may_add_data_ : 1; // Whether this output section needs a STT_SECTION symbol in the // normal symbol table. This will be true if there is a relocation // which needs it. diff --git a/gold/po/POTFILES.in b/gold/po/POTFILES.in index 834e31aacb0..0c4145af71a 100644 --- a/gold/po/POTFILES.in +++ b/gold/po/POTFILES.in @@ -17,6 +17,8 @@ gold-threads.h i386.cc layout.cc layout.h +merge.cc +merge.h object.cc object.h options.cc diff --git a/gold/po/gold.pot b/gold/po/gold.pot index f89d7cef0ba..79d0628dc44 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-05 17:51-0800\n" +"POT-Creation-Date: 2007-05-16 10:40-0700\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" @@ -101,7 +101,7 @@ msgstr "" msgid "%s: %s: dynamic symbol table name section has wrong type: %u\n" msgstr "" -#: dynobj.cc:368 object.cc:421 +#: dynobj.cc:368 object.cc:420 #, c-format msgid "%s: %s: bad section name offset for section %u: %lu\n" msgstr "" @@ -255,7 +255,7 @@ msgstr "" msgid "%s: missing expected TLS relocation\n" msgstr "" -#: i386.cc:729 i386.cc:870 i386.cc:1125 +#: i386.cc:729 i386.cc:870 i386.cc:1136 #, c-format msgid "%s: %s: unexpected reloc %u in object file\n" msgstr "" @@ -280,31 +280,42 @@ msgstr "" msgid "%s: %s: missing expected TLS relocation\n" msgstr "" -#: i386.cc:1157 i386.cc:1232 i386.cc:1243 +#: i386.cc:1168 i386.cc:1245 i386.cc:1256 #, c-format msgid "%s: %s: unsupported reloc %u\n" msgstr "" -#: i386.cc:1184 +#: i386.cc:1195 #, c-format msgid "%s: %s: TLS reloc but no TLS segment\n" msgstr "" -#: i386.cc:1217 +#: i386.cc:1230 #, c-format msgid "%s: %s: unsupported reloc type %u\n" msgstr "" -#: i386.cc:1426 +#: i386.cc:1439 #, c-format msgid "%s: %s: TLS relocation out of range\n" msgstr "" -#: i386.cc:1444 +#: i386.cc:1457 #, c-format msgid "%s: %s: TLS relocation against invalid instruction\n" msgstr "" +#: merge.cc:252 +#, c-format +msgid "" +"%s: %s: mergeable string section length not multiple of character size\n" +msgstr "" + +#: merge.cc:269 +#, c-format +msgid "%s: %s: entry in mergeable string section not null terminated\n" +msgstr "" + #: object.cc:30 #, c-format msgid "%s: %s: unsupported ELF machine number %d\n" @@ -315,32 +326,32 @@ msgstr "" msgid "%s: %s: section name section has wrong type: %u\n" msgstr "" -#: object.cc:229 +#: object.cc:228 #, c-format msgid "%s: %s: invalid symbol table name index: %u\n" msgstr "" -#: object.cc:237 +#: object.cc:236 #, c-format msgid "%s: %s: symbol table name section has wrong type: %u\n" msgstr "" -#: object.cc:293 +#: object.cc:292 #, c-format msgid "%s: %s: section group %u info %u out of range\n" msgstr "" -#: object.cc:310 +#: object.cc:309 #, c-format msgid "%s: %s: symbol %u name offset %u out of range\n" msgstr "" -#: object.cc:344 +#: object.cc:343 #, c-format msgid "%s: %s: section %u in section group %u out of range" msgstr "" -#: object.cc:488 +#: object.cc:487 #, c-format msgid "%s: %s: size of symbols is not multiple of symbol size\n" msgstr "" @@ -355,47 +366,47 @@ msgstr "" msgid "%s: %s: local symbol %u section index %u out of range\n" msgstr "" -#: object.cc:615 +#: object.cc:620 #, c-format msgid "%s: %s: local symbol %u section name out of range: %u >= %u\n" msgstr "" -#: object.cc:815 +#: object.cc:834 #, c-format msgid "%s: %s: unsupported ELF file type %d\n" msgstr "" -#: object.cc:834 object.cc:887 object.cc:908 +#: object.cc:853 object.cc:906 object.cc:927 #, c-format msgid "%s: %s: ELF file too short\n" msgstr "" -#: object.cc:843 +#: object.cc:862 #, c-format msgid "%s: %s: invalid ELF version 0\n" msgstr "" -#: object.cc:846 +#: object.cc:865 #, c-format msgid "%s: %s: unsupported ELF version %d\n" msgstr "" -#: object.cc:854 +#: object.cc:873 #, c-format msgid "%s: %s: invalid ELF class 0\n" msgstr "" -#: object.cc:861 +#: object.cc:880 #, c-format msgid "%s: %s: unsupported ELF class %d\n" msgstr "" -#: object.cc:869 +#: object.cc:888 #, c-format msgid "%s: %s: invalid ELF data encoding\n" msgstr "" -#: object.cc:876 +#: object.cc:895 #, c-format msgid "%s: %s: unsupported ELF data encoding %d\n" msgstr "" @@ -511,37 +522,37 @@ msgstr "" msgid "%s: -%c: %s\n" msgstr "" -#: output.cc:881 +#: output.cc:903 #, c-format msgid "%s: %s: invalid alignment %lu for section \"%s\"\n" msgstr "" -#: output.cc:1393 +#: output.cc:1519 #, c-format msgid "%s: %s: open: %s\n" msgstr "" -#: output.cc:1402 +#: output.cc:1528 #, c-format msgid "%s: %s: lseek: %s\n" msgstr "" -#: output.cc:1409 +#: output.cc:1535 #, c-format msgid "%s: %s: write: %s\n" msgstr "" -#: output.cc:1419 +#: output.cc:1545 #, c-format msgid "%s: %s: mmap: %s\n" msgstr "" -#: output.cc:1433 +#: output.cc:1559 #, c-format msgid "%s: %s: munmap: %s\n" msgstr "" -#: output.cc:1441 +#: output.cc:1567 #, c-format msgid "%s: %s: close: %s\n" msgstr "" @@ -562,22 +573,22 @@ msgstr "" msgid "%s: %s: not an object or archive\n" msgstr "" -#: reloc.cc:169 reloc.cc:410 +#: reloc.cc:169 reloc.cc:413 #, c-format msgid "%s: %s: relocation section %u has bad info %u\n" msgstr "" -#: reloc.cc:188 reloc.cc:427 +#: reloc.cc:188 reloc.cc:430 #, c-format msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n" msgstr "" -#: reloc.cc:204 reloc.cc:446 +#: reloc.cc:204 reloc.cc:449 #, c-format msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u" msgstr "" -#: reloc.cc:215 reloc.cc:457 +#: reloc.cc:215 reloc.cc:460 #, c-format msgid "%s: %s: reloc section %u size %lu uneven" msgstr "" @@ -632,12 +643,12 @@ msgstr "" msgid "%s: %s: warning: %s\n" msgstr "" -#: target-reloc.h:164 +#: target-reloc.h:170 #, c-format msgid "%s: %s: reloc has bad offset %zu\n" msgstr "" -#: target-reloc.h:174 +#: target-reloc.h:180 #, c-format msgid "%s: %s: undefined reference to '%s'\n" msgstr "" diff --git a/gold/reloc.cc b/gold/reloc.cc index 001fb01cc1e..76ab1961395 100644 --- a/gold/reloc.cc +++ b/gold/reloc.cc @@ -343,6 +343,9 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs, pvs->view = NULL; + if (map_sections[i].offset == -1) + continue; + const Output_section* os = map_sections[i].output_section; if (os == NULL) continue; diff --git a/gold/reloc.h b/gold/reloc.h index 1edaa579cee..1aa0d896717 100644 --- a/gold/reloc.h +++ b/gold/reloc.h @@ -13,13 +13,18 @@ namespace gold class General_options; class Relobj; class Read_relocs_data; -class Stringpool; class Symbol; class Layout; template<int size> class Sized_symbol; +template<int size, bool big_endian> +class Sized_relobj; + +template<int size> +class Symbol_value; + template<int sh_type, bool dynamic, int size, bool big_endian> class Output_data_reloc; @@ -151,6 +156,22 @@ private: elfcpp::Swap<valsize, big_endian>::writeval(wv, x + value); } + // Do a simple relocation using a Symbol_value with the addend in + // the section contents. VALSIZE is the size of the value to + // relocate. + template<int valsize> + static inline void + rel(unsigned char* view, + const Sized_relobj<size, big_endian>* object, + const Symbol_value<size>* psymval) + { + typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast<Valtype*>(view); + Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv); + x = psymval->value(object, x); + elfcpp::Swap<valsize, big_endian>::writeval(wv, x); + } + // Do a simple PC relative relocation with the addend in the section // contents. VALSIZE is the size of the value. template<int valsize> @@ -165,76 +186,129 @@ private: elfcpp::Swap<valsize, big_endian>::writeval(wv, x + value - address); } + // Do a simple PC relative relocation with a Symbol_value with the + // addend in the section contents. VALSIZE is the size of the + // value. + template<int valsize> + static inline void + pcrel(unsigned char* view, + const Sized_relobj<size, big_endian>* object, + const Symbol_value<size>* psymval, + typename elfcpp::Elf_types<size>::Elf_Addr address) + { + typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast<Valtype*>(view); + Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv); + x = psymval->value(object, x); + elfcpp::Swap<valsize, big_endian>::writeval(wv, x - address); + } + typedef Relocate_functions<size, big_endian> This; public: - // Do a simple 8-bit REL relocation with the addend in the object - // file data. + // Do a simple 8-bit REL relocation with the addend in the section + // contents. static inline void rel8(unsigned char* view, unsigned char value) - { - This::template rel<8>(view, value); - } + { This::template rel<8>(view, value); } + + static inline void + rel8(unsigned char* view, + const Sized_relobj<size, big_endian>* object, + const Symbol_value<size>* psymval) + { This::template rel<8>(view, object, psymval); } // Do a simple 8-bit PC relative relocation with the addend in the - // object file data. + // section contents. static inline void pcrel8(unsigned char* view, unsigned char value, typename elfcpp::Elf_types<size>::Elf_Addr address) - { - This::template pcrel<8>(view, value, address); - } + { This::template pcrel<8>(view, value, address); } + + static inline void + pcrel8(unsigned char* view, + const Sized_relobj<size, big_endian>* object, + const Symbol_value<size>* psymval, + typename elfcpp::Elf_types<size>::Elf_Addr address) + { This::template pcrel<8>(view, object, psymval, address); } - // Do a simple 16-bit REL relocation with the addend in the object - // file data. + // Do a simple 16-bit REL relocation with the addend in the section + // contents. static inline void rel16(unsigned char* view, elfcpp::Elf_Half value) - { - This::template rel<16>(view, value); - } + { This::template rel<16>(view, value); } + + static inline void + rel16(unsigned char* view, + const Sized_relobj<size, big_endian>* object, + const Symbol_value<size>* psymval) + { This::template rel<16>(view, object, psymval); } // Do a simple 32-bit PC relative REL relocation with the addend in - // the object file data. + // the section contents. static inline void pcrel16(unsigned char* view, elfcpp::Elf_Word value, typename elfcpp::Elf_types<size>::Elf_Addr address) - { - This::template pcrel<16>(view, value, address); - } + { This::template pcrel<16>(view, value, address); } + + static inline void + pcrel16(unsigned char* view, + const Sized_relobj<size, big_endian>* object, + const Symbol_value<size>* psymval, + typename elfcpp::Elf_types<size>::Elf_Addr address) + { This::template pcrel<16>(view, object, psymval, address); } // Do a simple 32-bit REL relocation with the addend in the section // contents. static inline void rel32(unsigned char* view, elfcpp::Elf_Word value) - { - This::template rel<32>(view, value); - } + { This::template rel<32>(view, value); } + + static inline void + rel32(unsigned char* view, + const Sized_relobj<size, big_endian>* object, + const Symbol_value<size>* psymval) + { This::template rel<32>(view, object, psymval); } // Do a simple 32-bit PC relative REL relocation with the addend in // the section contents. static inline void pcrel32(unsigned char* view, elfcpp::Elf_Word value, typename elfcpp::Elf_types<size>::Elf_Addr address) - { - This::template pcrel<32>(view, value, address); - } + { This::template pcrel<32>(view, value, address); } + + static inline void + pcrel32(unsigned char* view, + const Sized_relobj<size, big_endian>* object, + const Symbol_value<size>* psymval, + typename elfcpp::Elf_types<size>::Elf_Addr address) + { This::template pcrel<32>(view, object, psymval, address); } // Do a simple 64-bit REL relocation with the addend in the section // contents. static inline void rel64(unsigned char* view, elfcpp::Elf_Xword value) - { - This::template rel<64>(view, value); - } + { This::template rel<64>(view, value); } + + static inline void + rel64(unsigned char* view, + const Sized_relobj<size, big_endian>* object, + const Symbol_value<size>* psymval) + { This::template rel<64>(view, object, psymval); } // Do a simple 64-bit PC relative REL relocation with the addend in // the section contents. static inline void pcrel64(unsigned char* view, elfcpp::Elf_Xword value, typename elfcpp::Elf_types<size>::Elf_Addr address) - { - This::template pcrel<64>(view, value, address); - } + { This::template pcrel<64>(view, value, address); } + + static inline void + pcrel64(unsigned char* view, + const Sized_relobj<size, big_endian>* object, + const Symbol_value<size>* psymval, + typename elfcpp::Elf_types<size>::Elf_Addr address) + { This::template pcrel<64>(view, object, psymval, address); } }; // We try to avoid COPY relocations when possible. A COPY relocation diff --git a/gold/stringpool.cc b/gold/stringpool.cc index d53cf7792ff..34c11b4fc42 100644 --- a/gold/stringpool.cc +++ b/gold/stringpool.cc @@ -12,42 +12,103 @@ namespace gold { -Stringpool::Stringpool() - : string_set_(), strings_(), strtab_size_(0), next_index_(1) +template<typename Stringpool_char> +Stringpool_template<Stringpool_char>::Stringpool_template(bool zero_null) + : string_set_(), strings_(), strtab_size_(0), next_index_(1), + zero_null_(zero_null) { } -Stringpool::~Stringpool() +template<typename Stringpool_char> +Stringpool_template<Stringpool_char>::~Stringpool_template() { - for (std::list<Stringdata*>::iterator p = this->strings_.begin(); + for (typename std::list<Stringdata*>::iterator p = this->strings_.begin(); p != this->strings_.end(); ++p) delete[] reinterpret_cast<char*>(*p); } +// Return the length of a string of arbitrary character type. + +template<typename Stringpool_char> +size_t +Stringpool_template<Stringpool_char>::string_length(const Stringpool_char* p) +{ + size_t len = 0; + for (; *p != 0; ++p) + ++len; + return len; +} + +// Specialize string_length for char. Maybe we could just use +// std::char_traits<>::length? + +template<> +inline size_t +Stringpool_template<char>::string_length(const char* p) +{ + return strlen(p); +} + +// Equality comparison function. + +template<typename Stringpool_char> +bool +Stringpool_template<Stringpool_char>::Stringpool_eq::operator()( + const Stringpool_char* s1, + const Stringpool_char* s2) const +{ + while (*s1 != 0) + if (*s1++ != *s2++) + return false; + return *s2 == 0; +} + +// Specialize equality comparison for char. + +template<> +bool +Stringpool_template<char>::Stringpool_eq::operator()(const char* s1, + const char* s2) const +{ + return strcmp(s1, s2) == 0; +} + // Hash function. +template<typename Stringpool_char> size_t -Stringpool::Stringpool_hash::operator()(const char* s) const +Stringpool_template<Stringpool_char>::Stringpool_hash::operator()( + const Stringpool_char* s) const { // Fowler/Noll/Vo (FNV) hash (type FNV-1a). if (sizeof(size_t) == 8) { size_t result = static_cast<size_t>(14695981039346656037ULL); - while (*s != '\0') + while (*s != 0) { - result &= (size_t) *s++; - result *= 1099511628211ULL; + const char* p = reinterpret_cast<const char*>(s); + for (size_t i = 0; i < sizeof(Stringpool_char); ++i) + { + result &= (size_t) *p++; + result *= 1099511628211ULL; + } + ++s; } return result; } else { size_t result = 2166136261UL; - while (*s != '\0') + while (*s != 0) { - result ^= (size_t) *s++; - result *= 16777619UL; + const char* p = reinterpret_cast<const char*>(s); + for (size_t i = 0; i < sizeof(Stringpool_char); ++i) + { + result ^= (size_t) *p++; + result *= 16777619UL; + } + ++s; } return result; } @@ -56,8 +117,10 @@ Stringpool::Stringpool_hash::operator()(const char* s) const // Add a string to the list of canonical strings. Return a pointer to // the canonical string. If PKEY is not NULL, set *PKEY to the key. -const char* -Stringpool::add_string(const char* s, Key* pkey) +template<typename Stringpool_char> +const Stringpool_char* +Stringpool_template<Stringpool_char>::add_string(const Stringpool_char* s, + Key* pkey) { // We are in trouble if we've already computed the string offsets. gold_assert(this->strtab_size_ == 0); @@ -69,11 +132,11 @@ Stringpool::add_string(const char* s, Key* pkey) const size_t key_mult = 1024; gold_assert(key_mult >= buffer_size); - size_t len = strlen(s); + size_t len = (string_length(s) + 1) * sizeof(Stringpool_char); size_t alc; bool front = true; - if (len >= buffer_size) + if (len > buffer_size) { alc = sizeof(Stringdata) + len; front = false; @@ -83,26 +146,26 @@ Stringpool::add_string(const char* s, Key* pkey) else { Stringdata *psd = this->strings_.front(); - if (len >= psd->alc - psd->len) + if (len > psd->alc - psd->len) alc = sizeof(Stringdata) + buffer_size; else { char* ret = psd->data + psd->len; - memcpy(ret, s, len + 1); + memcpy(ret, s, len); if (pkey != NULL) *pkey = psd->index * key_mult + psd->len; - psd->len += len + 1; + psd->len += len; - return ret; + return reinterpret_cast<const Stringpool_char*>(ret); } } Stringdata *psd = reinterpret_cast<Stringdata*>(new char[alc]); psd->alc = alc - sizeof(Stringdata); - memcpy(psd->data, s, len + 1); - psd->len = len + 1; + memcpy(psd->data, s, len); + psd->len = len; psd->index = this->next_index_; ++this->next_index_; @@ -114,13 +177,14 @@ Stringpool::add_string(const char* s, Key* pkey) else this->strings_.push_back(psd); - return psd->data; + return reinterpret_cast<const Stringpool_char*>(psd->data); } // Add a string to a string pool. -const char* -Stringpool::add(const char* s, Key* pkey) +template<typename Stringpool_char> +const Stringpool_char* +Stringpool_template<Stringpool_char>::add(const Stringpool_char* s, Key* pkey) { // FIXME: This will look up the entry twice in the hash table. The // problem is that we can't insert S before we canonicalize it. I @@ -128,7 +192,7 @@ Stringpool::add(const char* s, Key* pkey) // unordered_map, so this should be replaced with custom code to do // what we need, which is to return the empty slot. - String_set_type::const_iterator p = this->string_set_.find(s); + typename String_set_type::const_iterator p = this->string_set_.find(s); if (p != this->string_set_.end()) { if (pkey != NULL) @@ -137,11 +201,12 @@ Stringpool::add(const char* s, Key* pkey) } Key k; - const char* ret = this->add_string(s, &k); + const Stringpool_char* ret = this->add_string(s, &k); const off_t ozero = 0; - std::pair<const char*, Val> element(ret, std::make_pair(k, ozero)); - std::pair<String_set_type::iterator, bool> ins = + std::pair<const Stringpool_char*, Val> element(ret, + std::make_pair(k, ozero)); + std::pair<typename String_set_type::iterator, bool> ins = this->string_set_.insert(element); gold_assert(ins.second); @@ -153,19 +218,23 @@ Stringpool::add(const char* s, Key* pkey) // Add a prefix of a string to a string pool. -const char* -Stringpool::add(const char* s, size_t len, Key* pkey) +template<typename Stringpool_char> +const Stringpool_char* +Stringpool_template<Stringpool_char>::add(const Stringpool_char* s, size_t len, + Key* pkey) { // FIXME: This implementation should be rewritten when we rewrite // the hash table to avoid copying. - std::string st(s, len); + std::basic_string<Stringpool_char> st(s, len); return this->add(st, pkey); } -const char* -Stringpool::find(const char* s, Key* pkey) const +template<typename Stringpool_char> +const Stringpool_char* +Stringpool_template<Stringpool_char>::find(const Stringpool_char* s, + Key* pkey) const { - String_set_type::const_iterator p = this->string_set_.find(s); + typename String_set_type::const_iterator p = this->string_set_.find(s); if (p == this->string_set_.end()) return NULL; @@ -186,19 +255,20 @@ Stringpool::find(const char* s, Key* pkey) const // in, but we need to ensure that suffixes wind up next to each other. // So we do a reversed lexicographic sort on the reversed string. +template<typename Stringpool_char> bool -Stringpool::Stringpool_sort_comparison::operator()( - String_set_type::iterator it1, - String_set_type::iterator it2) const +Stringpool_template<Stringpool_char>::Stringpool_sort_comparison::operator()( + typename String_set_type::iterator it1, + typename String_set_type::iterator it2) const { - const char* s1 = it1->first; - const char* s2 = it2->first; - int len1 = strlen(s1); - int len2 = strlen(s2); - int minlen = len1 < len2 ? len1 : len2; - const char* p1 = s1 + len1 - 1; - const char* p2 = s2 + len2 - 1; - for (int i = minlen - 1; i >= 0; --i, --p1, --p2) + const Stringpool_char* s1 = it1->first; + const Stringpool_char* s2 = it2->first; + size_t len1 = string_length(s1); + size_t len2 = string_length(s2); + size_t minlen = len1 < len2 ? len1 : len2; + const Stringpool_char* p1 = s1 + len1 - 1; + const Stringpool_char* p2 = s2 + len2 - 1; + for (size_t i = minlen; i > 0; --i, --p1, --p2) { if (*p1 != *p2) return *p1 > *p2; @@ -208,21 +278,24 @@ Stringpool::Stringpool_sort_comparison::operator()( // Return whether s1 is a suffix of s2. +template<typename Stringpool_char> bool -Stringpool::is_suffix(const char* s1, const char* s2) +Stringpool_template<Stringpool_char>::is_suffix(const Stringpool_char* s1, + const Stringpool_char* s2) { - size_t len1 = strlen(s1); - size_t len2 = strlen(s2); + size_t len1 = string_length(s1); + size_t len2 = string_length(s2); if (len1 > len2) return false; - return strcmp(s1, s2 + len2 - len1) == 0; + return memcmp(s1, s2 + len2 - len1, len1 * sizeof(Stringpool_char)) == 0; } // Turn the stringpool into an ELF strtab: determine the offsets of // each string in the table. +template<typename Stringpool_char> void -Stringpool::set_string_offsets() +Stringpool_template<Stringpool_char>::set_string_offsets() { if (this->strtab_size_ != 0) { @@ -232,30 +305,33 @@ Stringpool::set_string_offsets() size_t count = this->string_set_.size(); - std::vector<String_set_type::iterator> v; + std::vector<typename String_set_type::iterator> v; v.reserve(count); - for (String_set_type::iterator p = this->string_set_.begin(); + for (typename String_set_type::iterator p = this->string_set_.begin(); p != this->string_set_.end(); ++p) v.push_back(p); std::sort(v.begin(), v.end(), Stringpool_sort_comparison()); - // Offset 0 is reserved for the empty string. - off_t offset = 1; + const size_t charsize = sizeof(Stringpool_char); + + // Offset 0 may be reserved for the empty string. + off_t offset = this->zero_null_ ? charsize : 0; for (size_t i = 0; i < count; ++i) { - if (v[i]->first[0] == '\0') + if (this->zero_null_ && v[i]->first[0] == 0) v[i]->second.second = 0; - else if (i > 0 && Stringpool::is_suffix(v[i]->first, v[i - 1]->first)) + else if (i > 0 && is_suffix(v[i]->first, v[i - 1]->first)) v[i]->second.second = (v[i - 1]->second.second - + strlen(v[i - 1]->first) - - strlen(v[i]->first)); + + ((string_length(v[i - 1]->first) + - string_length(v[i]->first)) + * charsize)); else { v[i]->second.second = offset; - offset += strlen(v[i]->first) + 1; + offset += (string_length(v[i]->first) + 1) * charsize; } } @@ -265,11 +341,13 @@ Stringpool::set_string_offsets() // Get the offset of a string in the ELF strtab. The string must // exist. +template<typename Stringpool_char> off_t -Stringpool::get_offset(const char* s) const +Stringpool_template<Stringpool_char>::get_offset(const Stringpool_char* s) + const { gold_assert(this->strtab_size_ != 0); - String_set_type::const_iterator p = this->string_set_.find(s); + typename String_set_type::const_iterator p = this->string_set_.find(s); if (p != this->string_set_.end()) return p->second.second; gold_unreachable(); @@ -277,18 +355,32 @@ Stringpool::get_offset(const char* s) const // Write the ELF strtab into the output file at the specified offset. +template<typename Stringpool_char> void -Stringpool::write(Output_file* of, off_t offset) +Stringpool_template<Stringpool_char>::write(Output_file* of, off_t offset) { gold_assert(this->strtab_size_ != 0); unsigned char* viewu = of->get_output_view(offset, this->strtab_size_); char* view = reinterpret_cast<char*>(viewu); - view[0] = '\0'; - for (String_set_type::const_iterator p = this->string_set_.begin(); + if (this->zero_null_) + view[0] = '\0'; + for (typename String_set_type::const_iterator p = this->string_set_.begin(); p != this->string_set_.end(); ++p) - strcpy(view + p->second.second, p->first); + memcpy(view + p->second.second, p->first, + (string_length(p->first) + 1) * sizeof(Stringpool_char)); of->write_output_view(offset, this->strtab_size_, viewu); } +// Instantiate the templates we need. + +template +class Stringpool_template<char>; + +template +class Stringpool_template<uint16_t>; + +template +class Stringpool_template<uint32_t>; + } // End namespace gold. diff --git a/gold/stringpool.h b/gold/stringpool.h index 05c498e49fa..b9a65f6db98 100644 --- a/gold/stringpool.h +++ b/gold/stringpool.h @@ -14,7 +14,8 @@ namespace gold class Output_file; -class Stringpool +template<typename Stringpool_char> +class Stringpool_template { public: // The type of a key into the stringpool. A key value will always @@ -24,43 +25,47 @@ class Stringpool // into an unordered hash table. Zero is never a valid key. typedef size_t Key; - Stringpool(); + // Create a Stringpool. ZERO_NULL is true if we should reserve + // offset 0 to hold the empty string. + Stringpool_template(bool zero_null = true); - ~Stringpool(); + ~Stringpool_template(); // Add a string to the pool. This returns a canonical permanent // pointer to the string. If PKEY is not NULL, this sets *PKEY to // the key for the string. - const char* - add(const char*, Key* pkey); + const Stringpool_char* + add(const Stringpool_char*, Key* pkey); - const char* - add(const std::string& s, Key* pkey) + const Stringpool_char* + add(const std::basic_string<Stringpool_char>& s, Key* pkey) { return this->add(s.c_str(), pkey); } // Add the prefix of a string to the pool. - const char* - add(const char *, size_t, Key* pkey); + const Stringpool_char* + add(const Stringpool_char*, size_t, Key* pkey); // If a string is present, return the canonical string. Otherwise, // return NULL. If PKEY is not NULL, set *PKEY to the key. - const char* - find(const char*, Key* pkey) const; + const Stringpool_char* + find(const Stringpool_char*, Key* pkey) const; // Turn the stringpool into an ELF strtab: determine the offsets of // all the strings. void set_string_offsets(); - // Get the offset of a string in an ELF strtab. + // Get the offset of a string in an ELF strtab. This returns the + // offset in bytes, not characters. off_t - get_offset(const char*) const; + get_offset(const Stringpool_char*) const; off_t - get_offset(const std::string& s) const + get_offset(const std::basic_string<Stringpool_char>& s) const { return this->get_offset(s.c_str()); } - // Get the size of the ELF strtab. + // Get the size of the ELF strtab. This returns the number of + // bytes, not characters. off_t get_strtab_size() const { @@ -73,8 +78,12 @@ class Stringpool write(Output_file*, off_t offset); private: - Stringpool(const Stringpool&); - Stringpool& operator=(const Stringpool&); + Stringpool_template(const Stringpool_template&); + Stringpool_template& operator=(const Stringpool_template&); + + // Return the length of a string. + static size_t + string_length(const Stringpool_char*); // We store the actual data in a list of these buffers. struct Stringdata @@ -90,24 +99,24 @@ class Stringpool }; // Copy a string into the buffers, returning a canonical string. - const char* - add_string(const char*, Key*); + const Stringpool_char* + add_string(const Stringpool_char*, Key*); struct Stringpool_hash { size_t - operator()(const char*) const; + operator()(const Stringpool_char*) const; }; struct Stringpool_eq { bool - operator()(const char* p1, const char* p2) const - { return strcmp(p1, p2) == 0; } + operator()(const Stringpool_char* p1, const Stringpool_char* p2) const; }; // Return whether s1 is a suffix of s2. - static bool is_suffix(const char* s1, const char* s2); + static bool + is_suffix(const Stringpool_char* s1, const Stringpool_char* s2); // The hash table is a map from string names to a pair of Key and // ELF strtab offsets. We only use the offsets if we turn this into @@ -116,12 +125,13 @@ class Stringpool typedef std::pair<Key, off_t> Val; #ifdef HAVE_TR1_UNORDERED_SET - typedef Unordered_map<const char*, Val, Stringpool_hash, + typedef Unordered_map<const Stringpool_char*, Val, Stringpool_hash, Stringpool_eq, - std::allocator<std::pair<const char* const, Val> >, + std::allocator<std::pair<const Stringpool_char* const, + Val> >, true> String_set_type; #else - typedef Unordered_map<const char*, Val, Stringpool_hash, + typedef Unordered_map<const Stringpool_char*, Val, Stringpool_hash, Stringpool_eq> String_set_type; #endif @@ -130,8 +140,8 @@ class Stringpool struct Stringpool_sort_comparison { bool - operator()(String_set_type::iterator, - String_set_type::iterator) const; + operator()(typename String_set_type::iterator, + typename String_set_type::iterator) const; }; // List of Stringdata structures. @@ -145,8 +155,13 @@ class Stringpool off_t strtab_size_; // Next Stringdata index. unsigned int next_index_; + // Whether to reserve offset 0 to hold the null string. + bool zero_null_; }; +// The most common type of Stringpool. +typedef Stringpool_template<char> Stringpool; + } // End namespace gold. #endif // !defined(GOLD_STRINGPOOL_H) diff --git a/gold/target-reloc.h b/gold/target-reloc.h index 727de02e4e8..d282805dbeb 100644 --- a/gold/target-reloc.h +++ b/gold/target-reloc.h @@ -137,12 +137,13 @@ relocate_section( unsigned int r_type = elfcpp::elf_r_type<size>(r_info); const Sized_symbol<size>* sym; - typename elfcpp::Elf_types<size>::Elf_Addr value; + Symbol_value<size> symval; + const Symbol_value<size> *psymval; if (r_sym < local_count) { sym = NULL; - value = (*local_values)[r_sym]; + psymval = &(*local_values)[r_sym]; } else { @@ -152,10 +153,15 @@ relocate_section( gsym = relinfo->symtab->resolve_forwards(gsym); sym = static_cast<const Sized_symbol<size>*>(gsym); - value = sym->value(); + if (sym->has_symtab_index()) + symval.set_output_symtab_index(sym->symtab_index()); + else + symval.set_no_output_symtab_entry(); + symval.set_output_value(sym->value()); + psymval = &symval; } - if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, value, + if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, psymval, view + offset, view_address + offset, view_size)) continue; |