diff options
-rw-r--r-- | gold/ChangeLog | 30 | ||||
-rw-r--r-- | gold/arm.cc | 2 | ||||
-rw-r--r-- | gold/i386.cc | 2 | ||||
-rw-r--r-- | gold/output.cc | 70 | ||||
-rw-r--r-- | gold/output.h | 48 | ||||
-rw-r--r-- | gold/powerpc.cc | 122 | ||||
-rw-r--r-- | gold/sparc.cc | 3 | ||||
-rw-r--r-- | gold/target.h | 22 | ||||
-rw-r--r-- | gold/x86_64.cc | 2 |
9 files changed, 242 insertions, 59 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index c7488ef..e6ee0d6 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -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. diff --git a/gold/arm.cc b/gold/arm.cc index fc7d981..351c6fe 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -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); diff --git a/gold/i386.cc b/gold/i386.cc index b7f16eb..91611a1 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -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); diff --git a/gold/output.cc b/gold/output.cc index 664e408..d75579b 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -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; } diff --git a/gold/output.h b/gold/output.h index 14c5aac..d5bcc27 100644 --- a/gold/output.h +++ b/gold/output.h @@ -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; diff --git a/gold/powerpc.cc b/gold/powerpc.cc index f9a14ce..31f5ddf 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -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> diff --git a/gold/sparc.cc b/gold/sparc.cc index f8c59ec..04a88bf 100644 --- a/gold/sparc.cc +++ b/gold/sparc.cc @@ -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); } diff --git a/gold/target.h b/gold/target.h index effde15..65c15fc 100644 --- a/gold/target.h +++ b/gold/target.h @@ -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 diff --git a/gold/x86_64.cc b/gold/x86_64.cc index a15b6ae..1712beb 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -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); |