diff --git a/gold/object.cc b/gold/object.cc index 76d4630..8d50f50 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -427,7 +427,8 @@ Sized_relobj::do_for_all_local_got_entries( unsigned int nsyms = this->local_symbol_count(); for (unsigned int i = 0; i < nsyms; i++) { - Local_got_offsets::const_iterator p = this->local_got_offsets_.find(i); + Local_got_entry_key key(i, 0); + Local_got_offsets::const_iterator p = this->local_got_offsets_.find(key); if (p != this->local_got_offsets_.end()) { const Got_offset_list* got_offsets = p->second; diff --git a/gold/object.h b/gold/object.h index f796fb5..35fae4f 100644 --- a/gold/object.h +++ b/gold/object.h @@ -315,6 +315,57 @@ class Got_offset_list Got_offset_list* got_next_; }; +// The Local_got_entry_key used to index the GOT offsets for local +// non-TLS symbols, and tp-relative offsets for TLS symbols. +class Local_got_entry_key +{ + public: + Local_got_entry_key(unsigned int symndx, uint64_t addend) + : symndx_(symndx), addend_(addend) + {} + + // Whether this equals to another Local_got_entry_key. + bool + eq(const Local_got_entry_key& key) const + { + return ((this->symndx_ == key.symndx_) + && (this->addend_ == key.addend_)); + } + + // Compute a hash value for this using 64-bit FNV-1a hash. + size_t + hash_value() const + { + uint64_t h = 14695981039346656037ULL; // FNV offset basis. + uint64_t prime = 1099511628211ULL; + h = (h ^ static_cast(this->symndx_)) * prime; + h = (h ^ static_cast(this->addend_)) * prime; + return h; + } + + // Functors for associative containers. + struct equal_to + { + bool + operator()(const Local_got_entry_key& key1, + const Local_got_entry_key& key2) const + { return key1.eq(key2); } + }; + + struct hash + { + size_t + operator()(const Local_got_entry_key& key) const + { return key.hash_value(); } + }; + + private: + // The local symbol index. + unsigned int symndx_; + // The addend. + uint64_t addend_; +}; + // Type for mapping section index to uncompressed size and contents. struct Compressed_section_info @@ -1111,21 +1162,43 @@ class Relobj : public Object // GOT_TYPE. bool local_has_got_offset(unsigned int symndx, unsigned int got_type) const - { return this->do_local_has_got_offset(symndx, got_type); } + { return this->do_local_has_got_offset(symndx, got_type, 0); } + + // Return whether the local symbol SYMNDX plus ADDEND has a GOT offset + // of type GOT_TYPE. + bool + local_has_got_offset(unsigned int symndx, unsigned int got_type, + uint64_t addend) const + { return this->do_local_has_got_offset(symndx, got_type, addend); } // Return the GOT offset of type GOT_TYPE of the local symbol // SYMNDX. It is an error to call this if the symbol does not have // a GOT offset of the specified type. unsigned int local_got_offset(unsigned int symndx, unsigned int got_type) const - { return this->do_local_got_offset(symndx, got_type); } + { return this->do_local_got_offset(symndx, got_type, 0); } + + // Return the GOT offset of type GOT_TYPE of the local symbol + // SYMNDX plus ADDEND. It is an error to call this if the symbol + // does not have a GOT offset of the specified type. + unsigned int + local_got_offset(unsigned int symndx, unsigned int got_type, + uint64_t addend) const + { return this->do_local_got_offset(symndx, got_type, addend); } // Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX // to GOT_OFFSET. void set_local_got_offset(unsigned int symndx, unsigned int got_type, unsigned int got_offset) - { this->do_set_local_got_offset(symndx, got_type, got_offset); } + { this->do_set_local_got_offset(symndx, got_type, got_offset, 0); } + + // Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX + // plus ADDEND to GOT_OFFSET. + void + set_local_got_offset(unsigned int symndx, unsigned int got_type, + unsigned int got_offset, uint64_t addend) + { this->do_set_local_got_offset(symndx, got_type, got_offset, addend); } // Return whether the local symbol SYMNDX is a TLS symbol. bool @@ -1318,19 +1391,21 @@ class Relobj : public Object virtual unsigned int do_local_plt_offset(unsigned int symndx) const = 0; - // Return whether a local symbol has a GOT offset of a given type. + // Return whether a local symbol plus addend has a GOT offset + // of a given type. virtual bool do_local_has_got_offset(unsigned int symndx, - unsigned int got_type) const = 0; + unsigned int got_type, uint64_t addend) const = 0; - // Return the GOT offset of a given type of a local symbol. + // Return the GOT offset of a given type of a local symbol plus addend. virtual unsigned int - do_local_got_offset(unsigned int symndx, unsigned int got_type) const = 0; + do_local_got_offset(unsigned int symndx, unsigned int got_type, + uint64_t addend) const = 0; - // Set the GOT offset with a given type for a local symbol. + // Set the GOT offset with a given type for a local symbol plus addend. virtual void do_set_local_got_offset(unsigned int symndx, unsigned int got_type, - unsigned int got_offset) = 0; + unsigned int got_offset, uint64_t addend) = 0; // Return whether local symbol SYMNDX is a TLS symbol. virtual bool @@ -1993,24 +2068,28 @@ class Sized_relobj : public Relobj : convert_types(off)); } - // Return whether the local symbol SYMNDX has a GOT offset of type - // GOT_TYPE. + // Return whether the local symbol SYMNDX plus ADDEND has a GOT offset + // of type GOT_TYPE. bool - do_local_has_got_offset(unsigned int symndx, unsigned int got_type) const + do_local_has_got_offset(unsigned int symndx, unsigned int got_type, + uint64_t addend) const { + Local_got_entry_key key(symndx, addend); Local_got_offsets::const_iterator p = - this->local_got_offsets_.find(symndx); + this->local_got_offsets_.find(key); return (p != this->local_got_offsets_.end() && p->second->get_offset(got_type) != -1U); } // Return the GOT offset of type GOT_TYPE of the local symbol - // SYMNDX. + // SYMNDX plus ADDEND. unsigned int - do_local_got_offset(unsigned int symndx, unsigned int got_type) const + do_local_got_offset(unsigned int symndx, unsigned int got_type, + uint64_t addend) const { + Local_got_entry_key key(symndx, addend); Local_got_offsets::const_iterator p = - this->local_got_offsets_.find(symndx); + this->local_got_offsets_.find(key); gold_assert(p != this->local_got_offsets_.end()); unsigned int off = p->second->get_offset(got_type); gold_assert(off != -1U); @@ -2018,20 +2097,21 @@ class Sized_relobj : public Relobj } // Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX - // to GOT_OFFSET. + // plus ADDEND to GOT_OFFSET. void do_set_local_got_offset(unsigned int symndx, unsigned int got_type, - unsigned int got_offset) + unsigned int got_offset, uint64_t addend) { + Local_got_entry_key key(symndx, addend); Local_got_offsets::const_iterator p = - this->local_got_offsets_.find(symndx); + this->local_got_offsets_.find(key); if (p != this->local_got_offsets_.end()) p->second->set_offset(got_type, got_offset); else { Got_offset_list* g = new Got_offset_list(got_type, got_offset); std::pair ins = - this->local_got_offsets_.insert(std::make_pair(symndx, g)); + this->local_got_offsets_.insert(std::make_pair(key, g)); gold_assert(ins.second); } } @@ -2049,10 +2129,12 @@ class Sized_relobj : public Relobj private: // The GOT offsets of local symbols. This map also stores GOT offsets // for tp-relative offsets for TLS symbols. - typedef Unordered_map Local_got_offsets; + typedef Unordered_map Local_got_offsets; // GOT offsets for local non-TLS symbols, and tp-relative offsets - // for TLS symbols, indexed by symbol number. + // for TLS symbols, indexed by local got entry key class. Local_got_offsets local_got_offsets_; // For each input section, the offset of the input section in its // output section. This is INVALID_ADDRESS if the input section requires a diff --git a/gold/output.cc b/gold/output.cc index 5cc3629..5bcb6f3 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -1437,7 +1437,7 @@ Output_data_got::Got_entry::write( val = parameters->target().plt_address_for_local(object, lsi); else { - uint64_t lval = object->local_symbol_value(lsi, 0); + uint64_t lval = object->local_symbol_value(lsi, addend_); val = convert_types(lval); if (this->use_plt_or_tls_offset_ && is_tls) val += parameters->target().tls_offset_for_local(object, lsi, @@ -1548,6 +1548,27 @@ Output_data_got::add_local( return true; } +// Add an entry for a local symbol plus ADDEND to the GOT. This returns +// true if this is a new GOT entry, false if the symbol already has a GOT +// entry. + +template +bool +Output_data_got::add_local( + Relobj* object, + unsigned int symndx, + unsigned int got_type, + uint64_t addend) +{ + if (object->local_has_got_offset(symndx, got_type, addend)) + return false; + + unsigned int got_offset = this->add_got_entry(Got_entry(object, symndx, + false, addend)); + object->set_local_got_offset(symndx, got_type, got_offset, addend); + return true; +} + // Like add_local, but use the PLT offset. template @@ -1586,6 +1607,27 @@ Output_data_got::add_local_with_rel( rel_dyn->add_local_generic(object, symndx, r_type, this, got_offset, 0); } +// Add an entry for a local symbol plus ADDEND to the GOT, and add a dynamic +// relocation of type R_TYPE for the GOT entry. + +template +void +Output_data_got::add_local_with_rel( + Relobj* object, + unsigned int symndx, + unsigned int got_type, + Output_data_reloc_generic* rel_dyn, + unsigned int r_type, uint64_t addend) +{ + if (object->local_has_got_offset(symndx, got_type, addend)) + return; + + unsigned int got_offset = this->add_got_entry(Got_entry()); + object->set_local_got_offset(symndx, got_type, got_offset, addend); + rel_dyn->add_local_generic(object, symndx, r_type, this, got_offset, + addend); +} + // Add a pair of entries for a local symbol to the GOT, and add // a dynamic relocation of type R_TYPE using the section symbol of // the output section to which input section SHNDX maps, on the first. @@ -1612,6 +1654,32 @@ Output_data_got::add_local_pair_with_rel( rel_dyn->add_output_section_generic(os, r_type, this, got_offset, 0); } +// Add a pair of entries for a local symbol plus ADDEND to the GOT, and add +// a dynamic relocation of type R_TYPE using the section symbol of +// the output section to which input section SHNDX maps, on the first. +// The first got entry will have a value of zero, the second the +// value of the local symbol. +template +void +Output_data_got::add_local_pair_with_rel( + Relobj* object, + unsigned int symndx, + unsigned int shndx, + unsigned int got_type, + Output_data_reloc_generic* rel_dyn, + unsigned int r_type, uint64_t addend) +{ + if (object->local_has_got_offset(symndx, got_type, addend)) + return; + + unsigned int got_offset = + this->add_got_entry_pair(Got_entry(), + Got_entry(object, symndx, false, addend)); + object->set_local_got_offset(symndx, got_type, got_offset, addend); + Output_section* os = object->output_section(shndx); + rel_dyn->add_output_section_generic(os, r_type, this, got_offset, addend); +} + // Add a pair of entries for a local symbol to the GOT, and add // a dynamic relocation of type R_TYPE using STN_UNDEF on the first. // The first got entry will have a value of zero, the second the diff --git a/gold/output.h b/gold/output.h index c7ad54e..5b8c01c 100644 --- a/gold/output.h +++ b/gold/output.h @@ -2335,6 +2335,13 @@ class Output_data_got : public Output_data_got_base bool add_local(Relobj* object, unsigned int sym_index, unsigned int got_type); + // Add an entry for a local symbol plus ADDEND to the GOT. This returns + // true if this is a new GOT entry, false if the symbol already has a GOT + // entry. + bool + add_local(Relobj* object, unsigned int sym_index, unsigned int got_type, + uint64_t addend); + // Like add_local, but use the PLT offset of the local symbol if it // has one. bool @@ -2353,6 +2360,13 @@ class Output_data_got : public Output_data_got_base unsigned int got_type, Output_data_reloc_generic* rel_dyn, unsigned int r_type); + // Add an entry for a local symbol plus ADDEND to the GOT, and add a dynamic + // relocation of type R_TYPE for the GOT entry. + void + add_local_with_rel(Relobj* object, unsigned int sym_index, + unsigned int got_type, Output_data_reloc_generic* rel_dyn, + unsigned int r_type, uint64_t addend); + // Add a pair of entries for a local symbol to the GOT, and add // a dynamic relocation of type R_TYPE using the section symbol of // the output section to which input section SHNDX maps, on the first. @@ -2364,6 +2378,17 @@ class Output_data_got : public Output_data_got_base Output_data_reloc_generic* rel_dyn, unsigned int r_type); + // Add a pair of entries for a local symbol plus ADDEND to the GOT, and add + // a dynamic relocation of type R_TYPE using the section symbol of + // the output section to which input section SHNDX maps, on the first. + // The first got entry will have a value of zero, the second the + // value of the local symbol. + void + add_local_pair_with_rel(Relobj* object, unsigned int sym_index, + unsigned int shndx, unsigned int got_type, + Output_data_reloc_generic* rel_dyn, + unsigned int r_type, uint64_t addend); + // Add a pair of entries for a local symbol to the GOT, and add // a dynamic relocation of type R_TYPE using STN_UNDEF on the first. // The first got entry will have a value of zero, the second the @@ -2434,20 +2459,21 @@ class Output_data_got : public Output_data_got_base public: // Create a zero entry. Got_entry() - : local_sym_index_(RESERVED_CODE), use_plt_or_tls_offset_(false) + : local_sym_index_(RESERVED_CODE), use_plt_or_tls_offset_(false), + addend_(0) { this->u_.constant = 0; } // Create a global symbol entry. Got_entry(Symbol* gsym, bool use_plt_or_tls_offset) : local_sym_index_(GSYM_CODE), - use_plt_or_tls_offset_(use_plt_or_tls_offset) + use_plt_or_tls_offset_(use_plt_or_tls_offset), addend_(0) { this->u_.gsym = gsym; } // Create a local symbol entry. Got_entry(Relobj* object, unsigned int local_sym_index, bool use_plt_or_tls_offset) : local_sym_index_(local_sym_index), - use_plt_or_tls_offset_(use_plt_or_tls_offset) + use_plt_or_tls_offset_(use_plt_or_tls_offset), addend_(0) { gold_assert(local_sym_index != GSYM_CODE && local_sym_index != CONSTANT_CODE @@ -2456,6 +2482,19 @@ class Output_data_got : public Output_data_got_base this->u_.object = object; } + // Create a local symbol entry plus addend. + Got_entry(Relobj* object, unsigned int local_sym_index, + bool use_plt_or_tls_offset, uint64_t addend) + : local_sym_index_(local_sym_index), + use_plt_or_tls_offset_(use_plt_or_tls_offset), addend_(addend) + { + gold_assert(local_sym_index != GSYM_CODE + && local_sym_index != CONSTANT_CODE + && local_sym_index != RESERVED_CODE + && local_sym_index == this->local_sym_index_); + this->u_.object = object; + } + // Create a constant entry. The constant is a host value--it will // be swapped, if necessary, when it is written out. explicit Got_entry(Valtype constant) @@ -2489,6 +2528,8 @@ class Output_data_got : public Output_data_got_base // Whether to use the PLT offset of the symbol if it has one. // For TLS symbols, whether to offset the symbol value. bool use_plt_or_tls_offset_ : 1; + // The addend. + uint64_t addend_; }; typedef std::vector Got_entries;