diff options
Diffstat (limited to 'gold/x86_64.cc')
-rw-r--r-- | gold/x86_64.cc | 141 |
1 files changed, 121 insertions, 20 deletions
diff --git a/gold/x86_64.cc b/gold/x86_64.cc index f0aade4..585a499 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -65,7 +65,8 @@ class Target_x86_64 : public Target_freebsd<64, false> : Target_freebsd<64, false>(&x86_64_info), got_(NULL), plt_(NULL), got_plt_(NULL), global_offset_table_(NULL), rela_dyn_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY), dynbss_(NULL), - got_mod_index_offset_(-1U), tls_base_symbol_defined_(false) + got_mod_index_offset_(-1U), tlsdesc_reloc_info_(), + tls_base_symbol_defined_(false) { } // Hook for a new output section. @@ -161,6 +162,20 @@ class Target_x86_64 : public Target_freebsd<64, false> do_is_defined_by_abi(const Symbol* sym) const { return strcmp(sym->name(), "__tls_get_addr") == 0; } + // Return the symbol index to use for a target specific relocation. + // The only target specific relocation is R_X86_64_TLSDESC for a + // local symbol, which is an absolute reloc. + unsigned int + do_reloc_symbol_index(void*, unsigned int r_type) const + { + gold_assert(r_type == elfcpp::R_X86_64_TLSDESC); + return 0; + } + + // Return the addend to use for a target specific relocation. + uint64_t + do_reloc_addend(void* arg, unsigned int r_type, uint64_t addend) const; + // Adjust -fstack-split code which calls non-stack-split code. void do_calls_non_split(Relobj* object, unsigned int shndx, @@ -176,6 +191,14 @@ class Target_x86_64 : public Target_freebsd<64, false> return this->got_->data_size(); } + // Add a new reloc argument, returning the index in the vector. + size_t + add_tlsdesc_info(Sized_relobj<64, false>* object, unsigned int r_sym) + { + this->tlsdesc_reloc_info_.push_back(Tlsdesc_info(object, r_sym)); + return this->tlsdesc_reloc_info_.size() - 1; + } + private: // The class which scans relocations. class Scan @@ -379,6 +402,10 @@ class Target_x86_64 : public Target_freebsd<64, false> Reloc_section* rela_dyn_section(Layout*); + // Get the section to use for TLSDESC relocations. + Reloc_section* + rela_tlsdesc_section(Layout*) const; + // Add a potential copy relocation. void copy_reloc(Symbol_table* symtab, Layout* layout, @@ -404,6 +431,21 @@ class Target_x86_64 : public Target_freebsd<64, false> GOT_TYPE_TLS_DESC = 3 // GOT entry for TLS_DESC pair }; + // This type is used as the argument to the target specific + // relocation routines. The only target specific reloc is + // R_X86_64_TLSDESC against a local symbol. + struct Tlsdesc_info + { + Tlsdesc_info(Sized_relobj<64, false>* a_object, unsigned int a_r_sym) + : object(a_object), r_sym(a_r_sym) + { } + + // The object in which the local symbol is defined. + Sized_relobj<64, false>* object; + // The local symbol index in the object. + unsigned int r_sym; + }; + // The GOT section. Output_data_got<64, false>* got_; // The PLT section. @@ -420,6 +462,10 @@ class Target_x86_64 : public Target_freebsd<64, false> Output_data_space* dynbss_; // Offset of the GOT entry for the TLS module index. unsigned int got_mod_index_offset_; + // We handle R_X86_64_TLSDESC against a local symbol as a target + // specific relocation. Here we store the object and local symbol + // index for the relocation. + std::vector<Tlsdesc_info> tlsdesc_reloc_info_; // True if the _TLS_MODULE_BASE_ symbol has been defined. bool tls_base_symbol_defined_; }; @@ -551,11 +597,15 @@ class Output_data_plt_x86_64 : public Output_section_data get_tlsdesc_plt_offset() const { return (this->count_ + 1) * plt_entry_size; } - // Return the .rel.plt section data. + // Return the .rela.plt section data. const Reloc_section* - rel_plt() const + rela_plt() const { return this->rel_; } + // Return where the TLSDESC relocations should go. + Reloc_section* + rela_tlsdesc(Layout*); + protected: void do_adjust_output_section(Output_section* os); @@ -590,6 +640,9 @@ class Output_data_plt_x86_64 : public Output_section_data // The reloc section. Reloc_section* rel_; + // The TLSDESC relocs, if necessary. These must follow the regular + // PLT relocs. + Reloc_section* tlsdesc_rel_; // The .got section. Output_data_got<64, false>* got_; // The .got.plt section. @@ -607,8 +660,8 @@ class Output_data_plt_x86_64 : public Output_section_data Output_data_plt_x86_64::Output_data_plt_x86_64(Layout* layout, Output_data_got<64, false>* got, Output_data_space* got_plt) - : Output_section_data(8), got_(got), got_plt_(got_plt), count_(0), - tlsdesc_got_offset_(-1U) + : Output_section_data(8), tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt), + count_(0), tlsdesc_got_offset_(-1U) { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA, @@ -652,6 +705,24 @@ Output_data_plt_x86_64::add_entry(Symbol* gsym) // appear in the relocations. } +// Return where the TLSDESC relocations should go, creating it if +// necessary. These follow the JUMP_SLOT relocations. + +Output_data_plt_x86_64::Reloc_section* +Output_data_plt_x86_64::rela_tlsdesc(Layout* layout) +{ + if (this->tlsdesc_rel_ == NULL) + { + this->tlsdesc_rel_ = new Reloc_section(false); + layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA, + elfcpp::SHF_ALLOC, this->tlsdesc_rel_, + true, false, false, false); + gold_assert(this->tlsdesc_rel_->output_section() == + this->rel_->output_section()); + } + return this->tlsdesc_rel_; +} + // Set the final size. void Output_data_plt_x86_64::set_final_data_size() @@ -813,6 +884,14 @@ Target_x86_64::make_plt_section(Symbol_table* symtab, Layout* layout) } } +// Return the section for TLSDESC relocations. + +Target_x86_64::Reloc_section* +Target_x86_64::rela_tlsdesc_section(Layout* layout) const +{ + return this->plt_section()->rela_tlsdesc(layout); +} + // Create a PLT entry for a global symbol. void @@ -1199,18 +1278,21 @@ Target_x86_64::Scan::local(Symbol_table* symtab, Output_data_got<64, false>* got = target->got_section(symtab, layout); unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info()); - unsigned int shndx = lsym.get_st_shndx(); - bool is_ordinary; - shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary); - if (!is_ordinary) - object->error(_("local symbol %u has bad shndx %u"), - r_sym, shndx); - else - got->add_local_pair_with_rela(object, r_sym, - shndx, - GOT_TYPE_TLS_DESC, - target->rela_dyn_section(layout), - elfcpp::R_X86_64_TLSDESC, 0); + if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC)) + { + unsigned int got_offset = got->add_constant(0); + got->add_constant(0); + object->set_local_got_offset(r_sym, GOT_TYPE_TLS_DESC, + got_offset); + Reloc_section* rt = target->rela_tlsdesc_section(layout); + // We store the arguments we need in a vector, and + // use the index into the vector as the parameter + // to pass to the target specific routines. + uintptr_t intarg = target->add_tlsdesc_info(object, r_sym); + void* arg = reinterpret_cast<void*>(intarg); + rt->add_target_specific(elfcpp::R_X86_64_TLSDESC, arg, + got, got_offset, 0); + } } else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); @@ -1505,8 +1587,8 @@ Target_x86_64::Scan::global(Symbol_table* symtab, // Create a double GOT entry with an R_X86_64_TLSDESC reloc. Output_data_got<64, false>* got = target->got_section(symtab, layout); - got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_DESC, - target->rela_dyn_section(layout), + Reloc_section *rt = target->rela_tlsdesc_section(layout); + got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_DESC, rt, elfcpp::R_X86_64_TLSDESC, 0); } else if (optimized_type == tls::TLSOPT_TO_IE) @@ -1657,7 +1739,7 @@ Target_x86_64::do_finalize_sections( { const Reloc_section* rel_plt = (this->plt_ == NULL ? NULL - : this->plt_->rel_plt()); + : this->plt_->rela_plt()); layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt, this->rela_dyn_, true); @@ -2658,6 +2740,25 @@ Target_x86_64::do_code_fill(section_size_type length) const return std::string(nops[length], length); } +// Return the addend to use for a target specific relocation. The +// only target specific relocation is R_X86_64_TLSDESC for a local +// symbol. We want to set the addend is the offset of the local +// symbol in the TLS segment. + +uint64_t +Target_x86_64::do_reloc_addend(void* arg, unsigned int r_type, + uint64_t) const +{ + gold_assert(r_type == elfcpp::R_X86_64_TLSDESC); + uintptr_t intarg = reinterpret_cast<uintptr_t>(arg); + gold_assert(intarg < this->tlsdesc_reloc_info_.size()); + const Tlsdesc_info& ti(this->tlsdesc_reloc_info_[intarg]); + const Symbol_value<64>* psymval = ti.object->local_symbol(ti.r_sym); + gold_assert(psymval->is_tls_symbol()); + // The value of a TLS symbol is the offset in the TLS segment. + return psymval->value(ti.object, 0); +} + // FNOFFSET in section SHNDX in OBJECT is the start of a function // compiled with -fstack-split. The function calls non-stack-split // code. We have to change the function so that it always ensures |