From: Ian Lance Taylor Date: Mon, 29 Oct 2007 20:09:35 +0000 (+0000) Subject: From Craig Silverstein: better organization for TLS code. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=566221476275c4fdb5c0a32fbda95a7ce1f05f3b;p=binutils-gdb.git From Craig Silverstein: better organization for TLS code. --- diff --git a/gold/i386.cc b/gold/i386.cc index e36b22cdaf0..cfa10ad2fb1 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -162,27 +162,27 @@ class Target_i386 : public Sized_target<32, false> const Symbol_value<32>*, unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t); - // Do a TLS Initial-Exec to Local-Exec transition. - static inline void - tls_ie_to_le(const Relocate_info<32, false>*, size_t relnum, + // Do a TLS General-Dynamic to Local-Exec transition. + inline void + tls_gd_to_le(const Relocate_info<32, false>*, size_t relnum, Output_segment* tls_segment, const elfcpp::Rel<32, false>&, unsigned int r_type, elfcpp::Elf_types<32>::Elf_Addr value, unsigned char* view, off_t view_size); - // Do a TLS General-Dynamic to Local-Exec transition. + // Do a TLS Local-Dynamic to Local-Exec transition. inline void - tls_gd_to_le(const Relocate_info<32, false>*, size_t relnum, + tls_ld_to_le(const Relocate_info<32, false>*, size_t relnum, Output_segment* tls_segment, const elfcpp::Rel<32, false>&, unsigned int r_type, elfcpp::Elf_types<32>::Elf_Addr value, unsigned char* view, off_t view_size); - // Do a TLS Local-Dynamic to Local-Exec transition. - inline void - tls_ld_to_le(const Relocate_info<32, false>*, size_t relnum, + // Do a TLS Initial-Exec to Local-Exec transition. + static inline void + tls_ie_to_le(const Relocate_info<32, false>*, size_t relnum, Output_segment* tls_segment, const elfcpp::Rel<32, false>&, unsigned int r_type, elfcpp::Elf_types<32>::Elf_Addr value, @@ -814,57 +814,57 @@ Target_i386::Scan::local(const General_options&, // These are initial TLS relocs, which are expected when // linking. - case elfcpp::R_386_TLS_IE: - case elfcpp::R_386_TLS_GOTIE: - case elfcpp::R_386_TLS_LE: - case elfcpp::R_386_TLS_GD: - case elfcpp::R_386_TLS_LDM: - case elfcpp::R_386_TLS_LDO_32: + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: + case elfcpp::R_386_TLS_LDM: // Local-dynamic + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + case elfcpp::R_386_TLS_IE: // Initial-exec case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_LE: // Local-exec case elfcpp::R_386_TLS_LE_32: - case elfcpp::R_386_TLS_GOTDESC: - case elfcpp::R_386_TLS_DESC_CALL: { bool output_is_shared = parameters->output_is_shared(); const tls::Tls_optimization optimized_type = Target_i386::optimize_tls_reloc(!output_is_shared, r_type); switch (r_type) { - case elfcpp::R_386_TLS_LE: - case elfcpp::R_386_TLS_LE_32: - // FIXME: If generating a shared object, we need to copy - // this relocation into the object. - gold_assert(!output_is_shared); - break; - - case elfcpp::R_386_TLS_IE: - case elfcpp::R_386_TLS_IE_32: - case elfcpp::R_386_TLS_GOTIE: - // FIXME: If not relaxing to LE, we need to generate a - // TPOFF or TPOFF32 reloc. + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva) + case elfcpp::R_386_TLS_DESC_CALL: + // FIXME: If not relaxing to LE, we need to generate + // DTPMOD32 and DTPOFF32 relocs. if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); break; - case elfcpp::R_386_TLS_LDM: + case elfcpp::R_386_TLS_LDM: // Local-dynamic // FIXME: If not relaxing to LE, we need to generate a // DTPMOD32 reloc. if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); break; - case elfcpp::R_386_TLS_LDO_32: + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic break; - case elfcpp::R_386_TLS_GD: - case elfcpp::R_386_TLS_GOTDESC: - case elfcpp::R_386_TLS_DESC_CALL: - // FIXME: If not relaxing to LE, we need to generate - // DTPMOD32 and DTPOFF32 relocs. + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + // FIXME: If not relaxing to LE, we need to generate a + // TPOFF or TPOFF32 reloc. if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); break; + case elfcpp::R_386_TLS_LE: // Local-exec + case elfcpp::R_386_TLS_LE_32: + // FIXME: If generating a shared object, we need to copy + // this relocation into the object. + gold_assert(!output_is_shared); + break; + default: gold_unreachable(); } @@ -1018,57 +1018,57 @@ Target_i386::Scan::global(const General_options& options, // These are initial tls relocs, which are expected when // linking. - case elfcpp::R_386_TLS_IE: - case elfcpp::R_386_TLS_GOTIE: - case elfcpp::R_386_TLS_LE: - case elfcpp::R_386_TLS_GD: - case elfcpp::R_386_TLS_LDM: - case elfcpp::R_386_TLS_LDO_32: + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: + case elfcpp::R_386_TLS_LDM: // Local-dynamic + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + case elfcpp::R_386_TLS_IE: // Initial-exec case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_LE: // Local-exec case elfcpp::R_386_TLS_LE_32: - case elfcpp::R_386_TLS_GOTDESC: - case elfcpp::R_386_TLS_DESC_CALL: { const bool is_final = gsym->final_value_is_known(); const tls::Tls_optimization optimized_type = Target_i386::optimize_tls_reloc(is_final, r_type); switch (r_type) { - case elfcpp::R_386_TLS_LE: - case elfcpp::R_386_TLS_LE_32: - // FIXME: If generating a shared object, we need to copy - // this relocation into the object. - gold_assert(!parameters->output_is_shared()); - break; - - case elfcpp::R_386_TLS_IE: - case elfcpp::R_386_TLS_IE_32: - case elfcpp::R_386_TLS_GOTIE: - // FIXME: If not relaxing to LE, we need to generate a - // TPOFF or TPOFF32 reloc. + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: + // FIXME: If not relaxing to LE, we need to generate + // DTPMOD32 and DTPOFF32 relocs. if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_global(object, r_type, gsym); break; - case elfcpp::R_386_TLS_LDM: + case elfcpp::R_386_TLS_LDM: // Local-dynamic // FIXME: If not relaxing to LE, we need to generate a // DTPMOD32 reloc. if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_global(object, r_type, gsym); break; - case elfcpp::R_386_TLS_LDO_32: + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic break; - case elfcpp::R_386_TLS_GD: - case elfcpp::R_386_TLS_GOTDESC: - case elfcpp::R_386_TLS_DESC_CALL: - // FIXME: If not relaxing to LE, we need to generate - // DTPMOD32 and DTPOFF32 relocs. + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + // FIXME: If not relaxing to LE, we need to generate a + // TPOFF or TPOFF32 reloc. if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_global(object, r_type, gsym); break; + case elfcpp::R_386_TLS_LE: // Local-exec + case elfcpp::R_386_TLS_LE_32: + // FIXME: If generating a shared object, we need to copy + // this relocation into the object. + gold_assert(!parameters->output_is_shared()); + break; + default: gold_unreachable(); } @@ -1322,16 +1322,16 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, // These are initial tls relocs, which are expected when // linking. - case elfcpp::R_386_TLS_IE: - case elfcpp::R_386_TLS_GOTIE: - case elfcpp::R_386_TLS_LE: - case elfcpp::R_386_TLS_GD: - case elfcpp::R_386_TLS_LDM: - case elfcpp::R_386_TLS_LDO_32: + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: + case elfcpp::R_386_TLS_LDM: // Local-dynamic + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + case elfcpp::R_386_TLS_IE: // Initial-exec case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_LE: // Local-exec case elfcpp::R_386_TLS_LE_32: - case elfcpp::R_386_TLS_GOTDESC: - case elfcpp::R_386_TLS_DESC_CALL: this->relocate_tls(relinfo, relnum, rel, r_type, gsym, psymval, view, address, view_size); break; @@ -1386,24 +1386,12 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, = Target_i386::optimize_tls_reloc(is_final, r_type); switch (r_type) { - case elfcpp::R_386_TLS_LE_32: - value = tls_segment->vaddr() + tls_segment->memsz() - value; - Relocate_functions<32, false>::rel32(view, value); - break; - - case elfcpp::R_386_TLS_LE: - value = value - (tls_segment->vaddr() + tls_segment->memsz()); - Relocate_functions<32, false>::rel32(view, value); - break; - - case elfcpp::R_386_TLS_IE: - case elfcpp::R_386_TLS_GOTIE: - case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GD: // Global-dynamic if (optimized_type == tls::TLSOPT_TO_LE) { - Target_i386::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment, - rel, r_type, value, view, - view_size); + this->tls_gd_to_le(relinfo, relnum, tls_segment, + rel, r_type, value, view, + view_size); break; } gold_error_at_location(relinfo, relnum, rel.get_r_offset(), @@ -1411,20 +1399,14 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, r_type); break; - case elfcpp::R_386_TLS_GD: - if (optimized_type == tls::TLSOPT_TO_LE) - { - this->tls_gd_to_le(relinfo, relnum, tls_segment, - rel, r_type, value, view, - view_size); - break; - } + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: gold_error_at_location(relinfo, relnum, rel.get_r_offset(), _("unsupported reloc %u"), r_type); break; - case elfcpp::R_386_TLS_LDM: + case elfcpp::R_386_TLS_LDM: // Local-dynamic if (this->local_dynamic_type_ == LOCAL_DYNAMIC_SUN) { gold_error_at_location(relinfo, relnum, rel.get_r_offset(), @@ -1444,7 +1426,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, r_type); break; - case elfcpp::R_386_TLS_LDO_32: + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic // This reloc can appear in debugging sections, in which case we // won't see the TLS_LDM reloc. The local_dynamic_type field // tells us this. @@ -1458,109 +1440,31 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, Relocate_functions<32, false>::rel32(view, value); break; - case elfcpp::R_386_TLS_GOTDESC: - case elfcpp::R_386_TLS_DESC_CALL: + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_IE_32: + if (optimized_type == tls::TLSOPT_TO_LE) + { + Target_i386::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment, + rel, r_type, value, view, + view_size); + break; + } gold_error_at_location(relinfo, relnum, rel.get_r_offset(), _("unsupported reloc %u"), r_type); break; - } -} - -// Do a relocation in which we convert a TLS Initial-Exec to a -// Local-Exec. - -inline void -Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo, - size_t relnum, - Output_segment* tls_segment, - const elfcpp::Rel<32, false>& rel, - unsigned int r_type, - elfcpp::Elf_types<32>::Elf_Addr value, - unsigned char* view, - off_t view_size) -{ - // We have to actually change the instructions, which means that we - // need to examine the opcodes to figure out which instruction we - // are looking at. - if (r_type == elfcpp::R_386_TLS_IE) - { - // movl %gs:XX,%eax ==> movl $YY,%eax - // movl %gs:XX,%reg ==> movl $YY,%reg - // addl %gs:XX,%reg ==> addl $YY,%reg - tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -1); - tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4); - - unsigned char op1 = view[-1]; - if (op1 == 0xa1) - { - // movl XX,%eax ==> movl $YY,%eax - view[-1] = 0xb8; - } - else - { - tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); - unsigned char op2 = view[-2]; - if (op2 == 0x8b) - { - // movl XX,%reg ==> movl $YY,%reg - tls::check_tls(relinfo, relnum, rel.get_r_offset(), - (op1 & 0xc7) == 0x05); - view[-2] = 0xc7; - view[-1] = 0xc0 | ((op1 >> 3) & 7); - } - else if (op2 == 0x03) - { - // addl XX,%reg ==> addl $YY,%reg - tls::check_tls(relinfo, relnum, rel.get_r_offset(), - (op1 & 0xc7) == 0x05); - view[-2] = 0x81; - view[-1] = 0xc0 | ((op1 >> 3) & 7); - } - else - tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0); - } - } - else - { - // subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2 - // movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2 - // addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2 - tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); - tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4); + case elfcpp::R_386_TLS_LE: // Local-exec + value = value - (tls_segment->vaddr() + tls_segment->memsz()); + Relocate_functions<32, false>::rel32(view, value); + break; - unsigned char op1 = view[-1]; - unsigned char op2 = view[-2]; - tls::check_tls(relinfo, relnum, rel.get_r_offset(), - (op1 & 0xc0) == 0x80 && (op1 & 7) != 4); - if (op2 == 0x8b) - { - // movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2 - view[-2] = 0xc7; - view[-1] = 0xc0 | ((op1 >> 3) & 7); - } - else if (op2 == 0x2b) - { - // subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2 - view[-2] = 0x81; - view[-1] = 0xe8 | ((op1 >> 3) & 7); - } - else if (op2 == 0x03) - { - // addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2 - view[-2] = 0x81; - view[-1] = 0xc0 | ((op1 >> 3) & 7); - } - else - tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0); + case elfcpp::R_386_TLS_LE_32: + value = tls_segment->vaddr() + tls_segment->memsz() - value; + Relocate_functions<32, false>::rel32(view, value); + break; } - - value = tls_segment->vaddr() + tls_segment->memsz() - value; - if (r_type == elfcpp::R_386_TLS_IE || r_type == elfcpp::R_386_TLS_GOTIE) - value = - value; - - Relocate_functions<32, false>::rel32(view, value); } // Do a relocation in which we convert a TLS General-Dynamic to a @@ -1659,6 +1563,102 @@ Target_i386::Relocate::tls_ld_to_le(const Relocate_info<32, false>* relinfo, this->skip_call_tls_get_addr_ = true; } +// Do a relocation in which we convert a TLS Initial-Exec to a +// Local-Exec. + +inline void +Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo, + size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>& rel, + unsigned int r_type, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + off_t view_size) +{ + // We have to actually change the instructions, which means that we + // need to examine the opcodes to figure out which instruction we + // are looking at. + if (r_type == elfcpp::R_386_TLS_IE) + { + // movl %gs:XX,%eax ==> movl $YY,%eax + // movl %gs:XX,%reg ==> movl $YY,%reg + // addl %gs:XX,%reg ==> addl $YY,%reg + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -1); + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4); + + unsigned char op1 = view[-1]; + if (op1 == 0xa1) + { + // movl XX,%eax ==> movl $YY,%eax + view[-1] = 0xb8; + } + else + { + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); + + unsigned char op2 = view[-2]; + if (op2 == 0x8b) + { + // movl XX,%reg ==> movl $YY,%reg + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + (op1 & 0xc7) == 0x05); + view[-2] = 0xc7; + view[-1] = 0xc0 | ((op1 >> 3) & 7); + } + else if (op2 == 0x03) + { + // addl XX,%reg ==> addl $YY,%reg + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + (op1 & 0xc7) == 0x05); + view[-2] = 0x81; + view[-1] = 0xc0 | ((op1 >> 3) & 7); + } + else + tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0); + } + } + else + { + // subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2 + // movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2 + // addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2 + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4); + + unsigned char op1 = view[-1]; + unsigned char op2 = view[-2]; + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + (op1 & 0xc0) == 0x80 && (op1 & 7) != 4); + if (op2 == 0x8b) + { + // movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2 + view[-2] = 0xc7; + view[-1] = 0xc0 | ((op1 >> 3) & 7); + } + else if (op2 == 0x2b) + { + // subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2 + view[-2] = 0x81; + view[-1] = 0xe8 | ((op1 >> 3) & 7); + } + else if (op2 == 0x03) + { + // addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2 + view[-2] = 0x81; + view[-1] = 0xc0 | ((op1 >> 3) & 7); + } + else + tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0); + } + + value = tls_segment->vaddr() + tls_segment->memsz() - value; + if (r_type == elfcpp::R_386_TLS_IE || r_type == elfcpp::R_386_TLS_GOTIE) + value = - value; + + Relocate_functions<32, false>::rel32(view, value); +} + // Relocate section data. void diff --git a/gold/x86_64.cc b/gold/x86_64.cc index c520375a9d2..84c717d97dd 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -174,27 +174,27 @@ class Target_x86_64 : public Sized_target<64, false> const Symbol_value<64>*, unsigned char*, elfcpp::Elf_types<64>::Elf_Addr, off_t); - // Do a TLS Initial-Exec to Local-Exec transition. - static inline void - tls_ie_to_le(const Relocate_info<64, false>*, size_t relnum, + // Do a TLS General-Dynamic to Local-Exec transition. + inline void + tls_gd_to_le(const Relocate_info<64, false>*, size_t relnum, Output_segment* tls_segment, const elfcpp::Rela<64, false>&, unsigned int r_type, elfcpp::Elf_types<64>::Elf_Addr value, unsigned char* view, off_t view_size); - // Do a TLS General-Dynamic to Local-Exec transition. + // Do a TLS Local-Dynamic to Local-Exec transition. inline void - tls_gd_to_le(const Relocate_info<64, false>*, size_t relnum, + tls_ld_to_le(const Relocate_info<64, false>*, size_t relnum, Output_segment* tls_segment, const elfcpp::Rela<64, false>&, unsigned int r_type, elfcpp::Elf_types<64>::Elf_Addr value, unsigned char* view, off_t view_size); - // Do a TLS Local-Dynamic to Local-Exec transition. - inline void - tls_ld_to_le(const Relocate_info<64, false>*, size_t relnum, + // Do a TLS Initial-Exec to Local-Exec transition. + static inline void + tls_ie_to_le(const Relocate_info<64, false>*, size_t relnum, Output_segment* tls_segment, const elfcpp::Rela<64, false>&, unsigned int r_type, elfcpp::Elf_types<64>::Elf_Addr value, @@ -780,33 +780,29 @@ Target_x86_64::Scan::local(const General_options&, break; // These are initial tls relocs, which are expected when linking - case elfcpp::R_X86_64_TLSGD: - case elfcpp::R_X86_64_GOTPC32_TLSDESC: + case elfcpp::R_X86_64_TLSGD: // Global-dynamic + case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url) case elfcpp::R_X86_64_TLSDESC_CALL: - case elfcpp::R_X86_64_TLSLD: - case elfcpp::R_X86_64_GOTTPOFF: - case elfcpp::R_X86_64_TPOFF32: + case elfcpp::R_X86_64_TLSLD: // Local-dynamic case elfcpp::R_X86_64_DTPOFF32: case elfcpp::R_X86_64_DTPOFF64: + case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec + case elfcpp::R_X86_64_TPOFF32: // Local-exec { bool output_is_shared = parameters->output_is_shared(); const tls::Tls_optimization optimized_type = Target_x86_64::optimize_tls_reloc(!output_is_shared, r_type); switch (r_type) { - case elfcpp::R_X86_64_TPOFF32: // Local-exec - // FIXME: If generating a shared object, we need to copy - // this relocation into the object. - gold_assert(!output_is_shared); + case elfcpp::R_X86_64_TLSGD: // General-dynamic + case elfcpp::R_X86_64_GOTPC32_TLSDESC: + case elfcpp::R_X86_64_TLSDESC_CALL: + // FIXME: If not relaxing to LE, we need to generate + // DTPMOD64 and DTPOFF64 relocs. + if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_local(object, r_type); break; - case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec - // FIXME: If not relaxing to LE, we need to generate a - // TPOFF64 reloc. - if (optimized_type != tls::TLSOPT_TO_LE) - unsupported_reloc_local(object, r_type); - break; - case elfcpp::R_X86_64_TLSLD: // Local-dynamic case elfcpp::R_X86_64_DTPOFF32: case elfcpp::R_X86_64_DTPOFF64: @@ -816,14 +812,17 @@ Target_x86_64::Scan::local(const General_options&, unsupported_reloc_local(object, r_type); break; + case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec + // FIXME: If not relaxing to LE, we need to generate a + // TPOFF64 reloc. + if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_local(object, r_type); + break; - case elfcpp::R_X86_64_TLSGD: // General-dynamic - case elfcpp::R_X86_64_GOTPC32_TLSDESC: - case elfcpp::R_X86_64_TLSDESC_CALL: - // FIXME: If not relaxing to LE, we need to generate - // DTPMOD64 and DTPOFF64 relocs. - if (optimized_type != tls::TLSOPT_TO_LE) - unsupported_reloc_local(object, r_type); + case elfcpp::R_X86_64_TPOFF32: // Local-exec + // FIXME: If generating a shared object, we need to copy + // this relocation into the object. + gold_assert(!output_is_shared); break; default: @@ -966,33 +965,29 @@ Target_x86_64::Scan::global(const General_options& options, break; // These are initial tls relocs, which are expected for global() - case elfcpp::R_X86_64_TLSGD: - case elfcpp::R_X86_64_TLSLD: - case elfcpp::R_X86_64_GOTTPOFF: - case elfcpp::R_X86_64_TPOFF32: - case elfcpp::R_X86_64_GOTPC32_TLSDESC: + case elfcpp::R_X86_64_TLSGD: // Global-dynamic + case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url) case elfcpp::R_X86_64_TLSDESC_CALL: + case elfcpp::R_X86_64_TLSLD: // Local-dynamic case elfcpp::R_X86_64_DTPOFF32: case elfcpp::R_X86_64_DTPOFF64: + case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec + case elfcpp::R_X86_64_TPOFF32: // Local-exec { const bool is_final = gsym->final_value_is_known(); const tls::Tls_optimization optimized_type = Target_x86_64::optimize_tls_reloc(is_final, r_type); switch (r_type) { - case elfcpp::R_X86_64_TPOFF32: // Local-exec - // FIXME: If generating a shared object, we need to copy - // this relocation into the object. - gold_assert(is_final); + case elfcpp::R_X86_64_TLSGD: // General-dynamic + case elfcpp::R_X86_64_GOTPC32_TLSDESC: + case elfcpp::R_X86_64_TLSDESC_CALL: + // FIXME: If not relaxing to LE, we need to generate + // DTPMOD64 and DTPOFF64, or TLSDESC, relocs. + if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_global(object, r_type, gsym); break; - case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec - // FIXME: If not relaxing to LE, we need to generate a - // TPOFF64 reloc. - if (optimized_type != tls::TLSOPT_TO_LE) - unsupported_reloc_global(object, r_type, gsym); - break; - case elfcpp::R_X86_64_TLSLD: // Local-dynamic case elfcpp::R_X86_64_DTPOFF32: case elfcpp::R_X86_64_DTPOFF64: @@ -1002,14 +997,17 @@ Target_x86_64::Scan::global(const General_options& options, unsupported_reloc_global(object, r_type, gsym); break; + case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec + // FIXME: If not relaxing to LE, we need to generate a + // TPOFF64 reloc. + if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_global(object, r_type, gsym); + break; - case elfcpp::R_X86_64_TLSGD: // General-dynamic - case elfcpp::R_X86_64_GOTPC32_TLSDESC: - case elfcpp::R_X86_64_TLSDESC_CALL: - // FIXME: If not relaxing to LE, we need to generate - // DTPMOD64 and DTPOFF64, or TLSDESC, relocs. - if (optimized_type != tls::TLSOPT_TO_LE) - unsupported_reloc_global(object, r_type, gsym); + case elfcpp::R_X86_64_TPOFF32: // Local-exec + // FIXME: If generating a shared object, we need to copy + // this relocation into the object. + gold_assert(is_final); break; default: @@ -1316,14 +1314,14 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, break; // These are initial tls relocs, which are expected when linking - case elfcpp::R_X86_64_TLSGD: - case elfcpp::R_X86_64_TLSLD: - case elfcpp::R_X86_64_GOTTPOFF: - case elfcpp::R_X86_64_TPOFF32: - case elfcpp::R_X86_64_GOTPC32_TLSDESC: + case elfcpp::R_X86_64_TLSGD: // Global-dynamic + case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url) case elfcpp::R_X86_64_TLSDESC_CALL: + case elfcpp::R_X86_64_TLSLD: // Local-dynamic case elfcpp::R_X86_64_DTPOFF32: case elfcpp::R_X86_64_DTPOFF64: + case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec + case elfcpp::R_X86_64_TPOFF32: // Local-exec this->relocate_tls(relinfo, relnum, rela, r_type, gsym, psymval, view, address, view_size); break; @@ -1371,26 +1369,8 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo, = Target_x86_64::optimize_tls_reloc(is_final, r_type); switch (r_type) { - case elfcpp::R_X86_64_TPOFF32: // Local-exec reloc - value = value - (tls_segment->vaddr() + tls_segment->memsz()); - Relocate_functions<64, false>::rel32(view, value); - break; - - case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec reloc - if (optimized_type == tls::TLSOPT_TO_LE) - { - Target_x86_64::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment, - rela, r_type, value, view, - view_size); - break; - } - gold_error_at_location(relinfo, relnum, rela.get_r_offset(), - _("unsupported reloc type %u"), - r_type); - break; - - case elfcpp::R_X86_64_TLSGD: - case elfcpp::R_X86_64_GOTPC32_TLSDESC: + case elfcpp::R_X86_64_TLSGD: // Global-dynamic + case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url) case elfcpp::R_X86_64_TLSDESC_CALL: if (optimized_type == tls::TLSOPT_TO_LE) { @@ -1403,7 +1383,7 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo, _("unsupported reloc %u"), r_type); break; - case elfcpp::R_X86_64_TLSLD: + case elfcpp::R_X86_64_TLSLD: // Local-dynamic if (optimized_type == tls::TLSOPT_TO_LE) { this->tls_ld_to_le(relinfo, relnum, tls_segment, rela, r_type, @@ -1429,63 +1409,25 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo, value = value - tls_segment->vaddr(); Relocate_functions<64, false>::rel64(view, value); break; - } -} -// Do a relocation in which we convert a TLS Initial-Exec to a -// Local-Exec. - -inline void -Target_x86_64::Relocate::tls_ie_to_le(const Relocate_info<64, false>* relinfo, - size_t relnum, - Output_segment* tls_segment, - const elfcpp::Rela<64, false>& rela, - unsigned int, - elfcpp::Elf_types<64>::Elf_Addr value, - unsigned char* view, - off_t view_size) -{ - // We need to examine the opcodes to figure out which instruction we - // are looking at. - - // movq foo@gottpoff(%rip),%reg ==> movq $YY,%reg - // addq foo@gottpoff(%rip),%reg ==> addq $YY,%reg - - tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3); - tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4); - - unsigned char op1 = view[-3]; - unsigned char op2 = view[-2]; - unsigned char op3 = view[-1]; - unsigned char reg = op3 >> 3; + case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec + if (optimized_type == tls::TLSOPT_TO_LE) + { + Target_x86_64::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment, + rela, r_type, value, view, + view_size); + break; + } + gold_error_at_location(relinfo, relnum, rela.get_r_offset(), + _("unsupported reloc type %u"), + r_type); + break; - if (op2 == 0x8b) - { - // movq - if (op1 == 0x4c) - view[-3] = 0x49; - view[-2] = 0xc7; - view[-1] = 0xc0 | reg; - } - else if (reg == 4) - { - // Special handling for %rsp. - if (op1 == 0x4c) - view[-3] = 0x49; - view[-2] = 0x81; - view[-1] = 0xc0 | reg; - } - else - { - // addq - if (op1 == 0x4c) - view[-3] = 0x4d; - view[-2] = 0x8d; - view[-1] = 0x80 | reg | (reg << 3); + case elfcpp::R_X86_64_TPOFF32: // Local-exec + value = value - (tls_segment->vaddr() + tls_segment->memsz()); + Relocate_functions<64, false>::rel32(view, value); + break; } - - value = value - (tls_segment->vaddr() + tls_segment->memsz()); - Relocate_functions<64, false>::rela32(view, value, 0); } // Do a relocation in which we convert a TLS General-Dynamic to a @@ -1552,6 +1494,62 @@ Target_x86_64::Relocate::tls_ld_to_le(const Relocate_info<64, false>* relinfo, this->skip_call_tls_get_addr_ = true; } +// Do a relocation in which we convert a TLS Initial-Exec to a +// Local-Exec. + +inline void +Target_x86_64::Relocate::tls_ie_to_le(const Relocate_info<64, false>* relinfo, + size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rela<64, false>& rela, + unsigned int, + elfcpp::Elf_types<64>::Elf_Addr value, + unsigned char* view, + off_t view_size) +{ + // We need to examine the opcodes to figure out which instruction we + // are looking at. + + // movq foo@gottpoff(%rip),%reg ==> movq $YY,%reg + // addq foo@gottpoff(%rip),%reg ==> addq $YY,%reg + + tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3); + tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4); + + unsigned char op1 = view[-3]; + unsigned char op2 = view[-2]; + unsigned char op3 = view[-1]; + unsigned char reg = op3 >> 3; + + if (op2 == 0x8b) + { + // movq + if (op1 == 0x4c) + view[-3] = 0x49; + view[-2] = 0xc7; + view[-1] = 0xc0 | reg; + } + else if (reg == 4) + { + // Special handling for %rsp. + if (op1 == 0x4c) + view[-3] = 0x49; + view[-2] = 0x81; + view[-1] = 0xc0 | reg; + } + else + { + // addq + if (op1 == 0x4c) + view[-3] = 0x4d; + view[-2] = 0x8d; + view[-1] = 0x80 | reg | (reg << 3); + } + + value = value - (tls_segment->vaddr() + tls_segment->memsz()); + Relocate_functions<64, false>::rela32(view, value, 0); +} + // Relocate section data. void