* output.h (Output_data_got::add_global_tls, add_local_tls,

add_local_tls_pair): New functions.
	(Output_data_got::add_local_pair_with_rel): Remove second
	reloc param.  Expand comment.
	(Output_data_got::Got_entry): Rename use_plt_offset_ to
	use_plt_or_tls_offset_, similarly for constructor param.
	(Output_data_got::Got_entry::write): Add got_index param.
	* output.cc (Output_data_got::add_global_tls, add_local_tls,
	add_local_tls_pair): New functions.
	(Output_data_got::Got_entry::write): Handle tls symbols
	with use_plt_or_tls_offset_ set specially.
	(Output_data_got::add_local_pair_with_rel): Only one reloc.
	(Output_data_got::do_write): Replace iterator with index, pass
	index to entry write function.
	* target.h (Target::tls_offset_for_local, tls_offset_for_global,
	do_tls_offset_for_local, do_tls_offset_for_global): New functions.
	* arm.cc (Target_arm::Scan::local): Update add_local_pair_with_rel
	call.
	* i386.cc (Target_i386::Scan::local): Likewise.
	* sparc.cc (Target_sparc::Scan::local): Likewise.
	* x86_64.cc (Target_x86_64::Scan::local): Likewise.
	* powerpc.cc (Target_powerpc::do_tls_offset_for_local,
	do_tls_offset_for_global): New functions.
	(Target_powerpc::Scan::local): Correct TLS relocations and got
	entry values.
	(Target_powerpc::Scan::global): Don't emit unnecessary
	dynamic relocations on TLS GOT entries.
This commit is contained in:
Alan Modra 2012-09-10 23:05:54 +00:00
parent 00716ab174
commit bd73a62d77
9 changed files with 242 additions and 59 deletions

View File

@ -1,3 +1,33 @@
2012-09-11 Alan Modra <amodra@gmail.com>
* output.h (Output_data_got::add_global_tls, add_local_tls,
add_local_tls_pair): New functions.
(Output_data_got::add_local_pair_with_rel): Remove second
reloc param. Expand comment.
(Output_data_got::Got_entry): Rename use_plt_offset_ to
use_plt_or_tls_offset_, similarly for constructor param.
(Output_data_got::Got_entry::write): Add got_index param.
* output.cc (Output_data_got::add_global_tls, add_local_tls,
add_local_tls_pair): New functions.
(Output_data_got::Got_entry::write): Handle tls symbols
with use_plt_or_tls_offset_ set specially.
(Output_data_got::add_local_pair_with_rel): Only one reloc.
(Output_data_got::do_write): Replace iterator with index, pass
index to entry write function.
* target.h (Target::tls_offset_for_local, tls_offset_for_global,
do_tls_offset_for_local, do_tls_offset_for_global): New functions.
* arm.cc (Target_arm::Scan::local): Update add_local_pair_with_rel
call.
* i386.cc (Target_i386::Scan::local): Likewise.
* sparc.cc (Target_sparc::Scan::local): Likewise.
* x86_64.cc (Target_x86_64::Scan::local): Likewise.
* powerpc.cc (Target_powerpc::do_tls_offset_for_local,
do_tls_offset_for_global): New functions.
(Target_powerpc::Scan::local): Correct TLS relocations and got
entry values.
(Target_powerpc::Scan::global): Don't emit unnecessary
dynamic relocations on TLS GOT entries.
2012-09-10 Matthias Klose <doko@ubuntu.com>
* config.in: Disable sanity check for kfreebsd.

View File

@ -8068,7 +8068,7 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
got->add_local_pair_with_rel(object, r_sym, shndx,
GOT_TYPE_TLS_PAIR,
target->rel_dyn_section(layout),
elfcpp::R_ARM_TLS_DTPMOD32, 0);
elfcpp::R_ARM_TLS_DTPMOD32);
else
got->add_tls_gd32_with_static_reloc(GOT_TYPE_TLS_PAIR,
object, r_sym);

View File

@ -1874,7 +1874,7 @@ Target_i386::Scan::local(Symbol_table* symtab,
got->add_local_pair_with_rel(object, r_sym, shndx,
GOT_TYPE_TLS_PAIR,
target->rel_dyn_section(layout),
elfcpp::R_386_TLS_DTPMOD32, 0);
elfcpp::R_386_TLS_DTPMOD32);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);

View File

@ -1369,7 +1369,9 @@ Output_data_group<size, big_endian>::do_write(Output_file* of)
template<int size, bool big_endian>
void
Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
Output_data_got<size, big_endian>::Got_entry::write(
unsigned int got_indx,
unsigned char* pov) const
{
Valtype val = 0;
@ -1381,7 +1383,7 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
// link-time value, which will be relocated dynamically by a
// RELATIVE relocation.
Symbol* gsym = this->u_.gsym;
if (this->use_plt_offset_ && gsym->has_plt_offset())
if (this->use_plt_or_tls_offset_ && gsym->has_plt_offset())
val = (parameters->target().plt_address_for_global(gsym)
+ gsym->plt_offset());
else
@ -1392,6 +1394,9 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
// as small as possible.
sgsym = static_cast<Sized_symbol<size>*>(gsym);
val = sgsym->value();
if (this->use_plt_or_tls_offset_ && gsym->type() == elfcpp::STT_TLS)
val += parameters->target().tls_offset_for_global(gsym,
got_indx);
}
}
break;
@ -1409,19 +1414,24 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
default:
{
const Relobj* object = this->u_.object;
const Sized_relobj_file<size, big_endian>* object
= static_cast<Sized_relobj_file<size, big_endian>*>(this->u_.object);
const unsigned int lsi = this->local_sym_index_;
if (!this->use_plt_offset_)
{
uint64_t lval = object->local_symbol_value(lsi, 0);
val = convert_types<Valtype, uint64_t>(lval);
}
else
bool is_tls = object->local_symbol(lsi)->is_tls_symbol();
if (this->use_plt_or_tls_offset_ && !is_tls)
{
uint64_t plt_address =
parameters->target().plt_address_for_local(object, lsi);
val = plt_address + object->local_plt_offset(lsi);
}
else
{
uint64_t lval = object->local_symbol_value(lsi, 0);
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,
got_indx);
}
}
break;
}
@ -1566,8 +1576,10 @@ Output_data_got<size, big_endian>::add_local_with_rel(
}
// Add a pair of entries for a local symbol to the GOT, and add
// dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively.
// If R_TYPE_2 == 0, add the second entry with no relocation.
// 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 size, bool big_endian>
void
Output_data_got<size, big_endian>::add_local_pair_with_rel(
@ -1576,8 +1588,7 @@ Output_data_got<size, big_endian>::add_local_pair_with_rel(
unsigned int shndx,
unsigned int got_type,
Output_data_reloc_generic* rel_dyn,
unsigned int r_type_1,
unsigned int r_type_2)
unsigned int r_type)
{
if (object->local_has_got_offset(symndx, got_type))
return;
@ -1587,11 +1598,30 @@ Output_data_got<size, big_endian>::add_local_pair_with_rel(
Got_entry(object, symndx, false));
object->set_local_got_offset(symndx, got_type, got_offset);
Output_section* os = object->output_section(shndx);
rel_dyn->add_output_section_generic(os, r_type_1, this, got_offset, 0);
rel_dyn->add_output_section_generic(os, r_type, this, got_offset, 0);
}
if (r_type_2 != 0)
rel_dyn->add_output_section_generic(os, r_type_2, this,
got_offset + size / 8, 0);
// 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
// value of the local symbol offset by Target::tls_offset_for_local.
template<int size, bool big_endian>
void
Output_data_got<size, big_endian>::add_local_tls_pair(
Relobj* object,
unsigned int symndx,
unsigned int got_type,
Output_data_reloc_generic* rel_dyn,
unsigned int r_type)
{
if (object->local_has_got_offset(symndx, got_type))
return;
unsigned int got_offset
= this->add_got_entry_pair(Got_entry(),
Got_entry(object, symndx, true));
object->set_local_got_offset(symndx, got_type, got_offset);
rel_dyn->add_local_generic(object, 0, r_type, this, got_offset, 0);
}
// Reserve a slot in the GOT for a local symbol or the second slot of a pair.
@ -1634,11 +1664,9 @@ Output_data_got<size, big_endian>::do_write(Output_file* of)
unsigned char* const oview = of->get_output_view(off, oview_size);
unsigned char* pov = oview;
for (typename Got_entries::const_iterator p = this->entries_.begin();
p != this->entries_.end();
++p)
for (unsigned int i = 0; i < this->entries_.size(); ++i)
{
p->write(pov);
this->entries_[i].write(i, pov);
pov += add;
}

View File

@ -2246,6 +2246,12 @@ class Output_data_got : public Output_data_got_base
bool
add_global_plt(Symbol* gsym, unsigned int got_type);
// Like add_global, but for a TLS symbol where the value will be
// offset using Target::tls_offset_for_global
bool
add_global_tls(Symbol* gsym, unsigned int got_type)
{ return add_global_plt(gsym, got_type); }
// Add an entry for a global symbol to the GOT, and add a dynamic
// relocation of type R_TYPE for the GOT entry.
void
@ -2270,6 +2276,12 @@ class Output_data_got : public Output_data_got_base
bool
add_local_plt(Relobj* object, unsigned int sym_index, unsigned int got_type);
// Like add_local, but for a TLS symbol where the value will be
// offset using Target::tls_offset_for_local
bool
add_local_tls(Relobj* object, unsigned int sym_index, unsigned int got_type)
{ return add_local_plt(object, sym_index, got_type); }
// Add an entry for a local symbol to the GOT, and add a dynamic
// relocation of type R_TYPE for the GOT entry.
void
@ -2278,12 +2290,25 @@ class Output_data_got : public Output_data_got_base
unsigned int r_type);
// Add a pair of entries for a local symbol to the GOT, and add
// dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively.
// 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_1, unsigned int r_type_2);
unsigned int r_type);
// 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
// value of the local symbol offset by Target::tls_offset_for_local.
void
add_local_tls_pair(Relobj* object, unsigned int sym_index,
unsigned int got_type,
Output_data_reloc_generic* rel_dyn,
unsigned int r_type);
// Add a constant to the GOT. This returns the offset of the new
// entry from the start of the GOT.
@ -2342,18 +2367,20 @@ class Output_data_got : public Output_data_got_base
public:
// Create a zero entry.
Got_entry()
: local_sym_index_(RESERVED_CODE), use_plt_offset_(false)
: local_sym_index_(RESERVED_CODE), use_plt_or_tls_offset_(false)
{ this->u_.constant = 0; }
// Create a global symbol entry.
Got_entry(Symbol* gsym, bool use_plt_offset)
: local_sym_index_(GSYM_CODE), use_plt_offset_(use_plt_offset)
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)
{ this->u_.gsym = gsym; }
// Create a local symbol entry.
Got_entry(Relobj* object, unsigned int local_sym_index,
bool use_plt_offset)
: local_sym_index_(local_sym_index), use_plt_offset_(use_plt_offset)
bool use_plt_or_tls_offset)
: local_sym_index_(local_sym_index),
use_plt_or_tls_offset_(use_plt_or_tls_offset)
{
gold_assert(local_sym_index != GSYM_CODE
&& local_sym_index != CONSTANT_CODE
@ -2365,12 +2392,12 @@ class Output_data_got : public Output_data_got_base
// 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)
: local_sym_index_(CONSTANT_CODE), use_plt_offset_(false)
: local_sym_index_(CONSTANT_CODE), use_plt_or_tls_offset_(false)
{ this->u_.constant = constant; }
// Write the GOT entry to an output view.
void
write(unsigned char* pov) const;
write(unsigned int got_indx, unsigned char* pov) const;
private:
enum
@ -2393,7 +2420,8 @@ class Output_data_got : public Output_data_got_base
// for a global symbol, or CONSTANT_CODE for a constant.
unsigned int local_sym_index_ : 31;
// Whether to use the PLT offset of the symbol if it has one.
bool use_plt_offset_ : 1;
// For TLS symbols, whether to offset the symbol value.
bool use_plt_or_tls_offset_ : 1;
};
typedef std::vector<Got_entry> Got_entries;

View File

@ -270,6 +270,18 @@ class Target_powerpc : public Sized_target<size, big_endian>
uint64_t
do_dynsym_value(const Symbol*) const;
// Return the offset to use for the GOT_INDX'th got entry which is
// for a local tls symbol specified by OBJECT, SYMNDX.
int64_t
do_tls_offset_for_local(const Relobj* object,
unsigned int symndx,
unsigned int got_indx) const;
// Return the offset to use for the GOT_INDX'th got entry which is
// for global tls symbol GSYM.
int64_t
do_tls_offset_for_global(Symbol* gsym, unsigned int got_indx) const;
// Relocate a section.
void
relocate_section(const Relocate_info<size, big_endian>*,
@ -2349,7 +2361,7 @@ Target_powerpc<size, big_endian>::Scan::local(
Output_section* output_section,
const elfcpp::Rela<size, big_endian>& reloc,
unsigned int r_type,
const elfcpp::Sym<size, big_endian>& lsym)
const elfcpp::Sym<size, big_endian>& /* lsym */)
{
Powerpc_relobj<size, big_endian>* ppc_object
= static_cast<Powerpc_relobj<size, big_endian>*>(object);
@ -2523,16 +2535,9 @@ Target_powerpc<size, big_endian>::Scan::local(
Output_data_got_powerpc<size, big_endian>* got
= target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
gold_assert(is_ordinary);
got->add_local_pair_with_rel(object, r_sym,
shndx,
GOT_TYPE_TLSGD,
target->rela_dyn_section(layout),
elfcpp::R_POWERPC_DTPMOD,
elfcpp::R_POWERPC_DTPREL);
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
got->add_local_tls_pair(object, r_sym, GOT_TYPE_TLSGD,
rela_dyn, elfcpp::R_POWERPC_DTPMOD);
}
else if (tls_type == tls::TLSOPT_TO_LE)
{
@ -2574,9 +2579,7 @@ Target_powerpc<size, big_endian>::Scan::local(
Output_data_got_powerpc<size, big_endian>* got
= target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
got->add_local_with_rel(object, r_sym, GOT_TYPE_DTPREL,
target->rela_dyn_section(layout),
elfcpp::R_POWERPC_DTPREL);
got->add_local_tls(object, r_sym, GOT_TYPE_DTPREL);
}
break;
@ -2591,9 +2594,7 @@ Target_powerpc<size, big_endian>::Scan::local(
Output_data_got_powerpc<size, big_endian>* got
= target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
got->add_local_with_rel(object, r_sym, GOT_TYPE_TPREL,
target->rela_dyn_section(layout),
elfcpp::R_POWERPC_TPREL);
got->add_local_tls(object, r_sym, GOT_TYPE_TPREL);
}
else if (tls_type == tls::TLSOPT_TO_LE)
{
@ -2913,9 +2914,15 @@ Target_powerpc<size, big_endian>::Scan::global(
{
Output_data_got_powerpc<size, big_endian>* got
= target->got_section(symtab, layout);
got->add_global_with_rel(gsym, GOT_TYPE_DTPREL,
target->rela_dyn_section(layout),
elfcpp::R_POWERPC_DTPREL);
if (!gsym->final_value_is_known()
&& (gsym->is_from_dynobj()
|| gsym->is_undefined()
|| gsym->is_preemptible()))
got->add_global_with_rel(gsym, GOT_TYPE_DTPREL,
target->rela_dyn_section(layout),
elfcpp::R_POWERPC_DTPREL);
else
got->add_global_tls(gsym, GOT_TYPE_DTPREL);
}
break;
@ -2930,9 +2937,15 @@ Target_powerpc<size, big_endian>::Scan::global(
{
Output_data_got_powerpc<size, big_endian>* got
= target->got_section(symtab, layout);
got->add_global_with_rel(gsym, GOT_TYPE_TPREL,
target->rela_dyn_section(layout),
elfcpp::R_POWERPC_TPREL);
if (!gsym->final_value_is_known()
&& (gsym->is_from_dynobj()
|| gsym->is_undefined()
|| gsym->is_preemptible()))
got->add_global_with_rel(gsym, GOT_TYPE_TPREL,
target->rela_dyn_section(layout),
elfcpp::R_POWERPC_TPREL);
else
got->add_global_tls(gsym, GOT_TYPE_TPREL);
}
else if (tls_type == tls::TLSOPT_TO_LE)
{
@ -4421,6 +4434,69 @@ Target_powerpc<size, big_endian>::do_dynsym_value(const Symbol* gsym) const
gold_unreachable();
}
// Return the offset to use for the GOT_INDX'th got entry which is
// for a local tls symbol specified by OBJECT, SYMNDX.
template<int size, bool big_endian>
int64_t
Target_powerpc<size, big_endian>::do_tls_offset_for_local(
const Relobj* object,
unsigned int symndx,
unsigned int got_indx) const
{
const Powerpc_relobj<size, big_endian>* ppc_object
= static_cast<const Powerpc_relobj<size, big_endian>*>(object);
if (ppc_object->local_symbol(symndx)->is_tls_symbol())
{
for (Got_type got_type = GOT_TYPE_TLSGD;
got_type <= GOT_TYPE_TPREL;
got_type = Got_type(got_type + 1))
if (ppc_object->local_has_got_offset(symndx, got_type))
{
unsigned int off = ppc_object->local_got_offset(symndx, got_type);
if (got_type == GOT_TYPE_TLSGD)
off += size / 8;
if (off == got_indx * (size / 8))
{
if (got_type == GOT_TYPE_TPREL)
return -tp_offset;
else
return -dtp_offset;
}
}
}
gold_unreachable();
}
// Return the offset to use for the GOT_INDX'th got entry which is
// for global tls symbol GSYM.
template<int size, bool big_endian>
int64_t
Target_powerpc<size, big_endian>::do_tls_offset_for_global(
Symbol* gsym,
unsigned int got_indx) const
{
if (gsym->type() == elfcpp::STT_TLS)
{
for (Got_type got_type = GOT_TYPE_TLSGD;
got_type <= GOT_TYPE_TPREL;
got_type = Got_type(got_type + 1))
if (gsym->has_got_offset(got_type))
{
unsigned int off = gsym->got_offset(got_type);
if (got_type == GOT_TYPE_TLSGD)
off += size / 8;
if (off == got_indx * (size / 8))
{
if (got_type == GOT_TYPE_TPREL)
return -tp_offset;
else
return -dtp_offset;
}
}
}
gold_unreachable();
}
// The selector for powerpc object files.
template<int size, bool big_endian>

View File

@ -2429,8 +2429,7 @@ Target_sparc<size, big_endian>::Scan::local(
target->rela_dyn_section(layout),
(size == 64
? elfcpp::R_SPARC_TLS_DTPMOD64
: elfcpp::R_SPARC_TLS_DTPMOD32),
0);
: elfcpp::R_SPARC_TLS_DTPMOD32));
if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
generate_tls_call(symtab, layout, target);
}

View File

@ -270,6 +270,20 @@ class Target
plt_address_for_local(const Relobj* object, unsigned int symndx) const
{ return this->do_plt_address_for_local(object, symndx); }
// Return the offset to use for the GOT_INDX'th got entry which is
// for a local tls symbol specified by OBJECT, SYMNDX.
int64_t
tls_offset_for_local(const Relobj* object,
unsigned int symndx,
unsigned int got_indx) const
{ return do_tls_offset_for_local(object, symndx, got_indx); }
// Return the offset to use for the GOT_INDX'th got entry which is
// for global tls symbol GSYM.
int64_t
tls_offset_for_global(Symbol* gsym, unsigned int got_indx) const
{ return do_tls_offset_for_global(gsym, got_indx); }
// Return whether this target can use relocation types to determine
// if a function's address is taken.
bool
@ -546,6 +560,14 @@ class Target
do_plt_address_for_local(const Relobj*, unsigned int) const
{ gold_unreachable(); }
virtual int64_t
do_tls_offset_for_local(const Relobj*, unsigned int, unsigned int) const
{ gold_unreachable(); }
virtual int64_t
do_tls_offset_for_global(Symbol*, unsigned int) const
{ gold_unreachable(); }
// Virtual function which may be overriden by the child class.
virtual bool
do_can_check_for_function_pointers() const

View File

@ -2477,7 +2477,7 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab,
shndx,
GOT_TYPE_TLS_PAIR,
target->rela_dyn_section(layout),
elfcpp::R_X86_64_DTPMOD64, 0);
elfcpp::R_X86_64_DTPMOD64);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);