Take addend into account when making GOT entries for local symbols.

gold/
	* object.cc (Sized_relobj::do_for_all_local_got_entries): Use
	Local_got_entry_key for searching in local_got_offsets_.
	* object.h (class Local_got_entry_key): New class.
	(Relobj::local_has_got_offset): New overloaded method.
	(Relobj::local_got_offset): Likewise.
	(Relobj::set_local_got_offset): Likewise.
	(Relobj::do_local_has_got_offset): Add addend argument.
	(Relobj::do_local_got_offset): Likewise.
	(Relobj::do_set_local_got_offset): Likewise.
	(Sized_relobj::do_local_has_got_offset): Add addend argument, and use
	Local_got_entry_key for searching through local_got_offsets_.
	(Sized_relobj::do_local_got_offset): Likewise.
	(Sized_relobj::do_set_local_got_offset): Likewise.
	(Sized_relobj::Local_got_offsets): Change type of the key from
	unsigned int to Local_got_entry_key, and add hash and equal_to.
	* output.cc (Got_entry::write): Take addend into account for
	calculating value of the local symbol for GOT.
	(Output_data_got::add_local): New definition of overloaded method.
	(Output_data_got::add_local_with_rel): Likewise.
	(Output_data_got::add_local_pair_with_rel): Likewise.
	* output.h (Output_data_got::add_local): New declaration of overloaded
	method.
This commit is contained in:
Vladimir Radosavljevic 2015-12-03 15:29:17 -08:00 committed by Cary Coutant
parent e58c48b4c8
commit 7ef8ae7c5f
5 changed files with 244 additions and 27 deletions

View File

@ -1,3 +1,28 @@
2015-12-03 Vladimir Radosavljevic <Vladimir.Radosavljevic@imgtec.com>
* object.cc (Sized_relobj::do_for_all_local_got_entries): Use
Local_got_entry_key for searching in local_got_offsets_.
* object.h (class Local_got_entry_key): New class.
(Relobj::local_has_got_offset): New overloaded method.
(Relobj::local_got_offset): Likewise.
(Relobj::set_local_got_offset): Likewise.
(Relobj::do_local_has_got_offset): Add addend argument.
(Relobj::do_local_got_offset): Likewise.
(Relobj::do_set_local_got_offset): Likewise.
(Sized_relobj::do_local_has_got_offset): Add addend argument, and use
Local_got_entry_key for searching through local_got_offsets_.
(Sized_relobj::do_local_got_offset): Likewise.
(Sized_relobj::do_set_local_got_offset): Likewise.
(Sized_relobj::Local_got_offsets): Change type of the key from
unsigned int to Local_got_entry_key, and add hash and equal_to.
* output.cc (Got_entry::write): Take addend into account for
calculating value of the local symbol for GOT.
(Output_data_got::add_local): New definition of overloaded method.
(Output_data_got::add_local_with_rel): Likewise.
(Output_data_got::add_local_pair_with_rel): Likewise.
* output.h (Output_data_got::add_local): New declaration of overloaded
method.
2015-11-25 Cary Coutant <ccoutant@gmail.com>
PR gold/19291

View File

@ -427,7 +427,8 @@ Sized_relobj<size, big_endian>::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;

View File

@ -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<uint64_t>(this->symndx_)) * prime;
h = (h ^ static_cast<uint64_t>(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<Address, uint64_t>(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<Local_got_offsets::iterator, bool> 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<unsigned int, Got_offset_list*> Local_got_offsets;
typedef Unordered_map<Local_got_entry_key, Got_offset_list*,
Local_got_entry_key::hash,
Local_got_entry_key::equal_to> 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

View File

@ -1437,7 +1437,7 @@ Output_data_got<got_size, big_endian>::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, this->addend_);
val = convert_types<Valtype, uint64_t>(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<got_size, big_endian>::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<int got_size, bool big_endian>
bool
Output_data_got<got_size, big_endian>::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<int got_size, bool big_endian>
@ -1586,6 +1607,27 @@ Output_data_got<got_size, big_endian>::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<int got_size, bool big_endian>
void
Output_data_got<got_size, big_endian>::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<got_size, big_endian>::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<int got_size, bool big_endian>
void
Output_data_got<got_size, big_endian>::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

View File

@ -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_entry> Got_entries;