+// Do a relocation in which we convert a TLS General-Dynamic to an
+// Initial-Exec.
+
+inline void
+Target_x86_64::Relocate::tls_gd_to_ie(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,
+ section_size_type view_size)
+{
+ // .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
+ // .word 0x6666; rex64; call __tls_get_addr
+ // ==> movq %fs:0,%rax; addq x@gottpoff(%rip),%rax
+
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -4);
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12);
+
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0));
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
+
+ memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0", 16);
+
+ value -= tls_segment->memsz();
+ Relocate_functions<64, false>::rela32(view + 8, value, 0);
+
+ // The next reloc should be a PLT32 reloc against __tls_get_addr.
+ // We can skip it.
+ this->skip_call_tls_get_addr_ = true;
+}
+
+// Do a relocation in which we convert a TLS General-Dynamic to a
+// Local-Exec.
+
+inline void
+Target_x86_64::Relocate::tls_gd_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,
+ section_size_type view_size)
+{
+ // .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
+ // .word 0x6666; rex64; call __tls_get_addr
+ // ==> movq %fs:0,%rax; leaq x@tpoff(%rax),%rax
+
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -4);
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12);
+
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0));
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
+
+ memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0\0", 16);
+
+ value -= tls_segment->memsz();
+ Relocate_functions<64, false>::rela32(view + 8, value, 0);
+
+ // The next reloc should be a PLT32 reloc against __tls_get_addr.
+ // We can skip it.
+ this->skip_call_tls_get_addr_ = true;
+}
+
+inline void
+Target_x86_64::Relocate::tls_ld_to_le(const Relocate_info<64, false>* relinfo,
+ size_t relnum,
+ Output_segment*,
+ const elfcpp::Rela<64, false>& rela,
+ unsigned int,
+ elfcpp::Elf_types<64>::Elf_Addr,
+ unsigned char* view,
+ section_size_type view_size)
+{
+ // leaq foo@tlsld(%rip),%rdi; call __tls_get_addr@plt;
+ // ... leq foo@dtpoff(%rax),%reg
+ // ==> .word 0x6666; .byte 0x66; movq %fs:0,%rax ... leaq x@tpoff(%rax),%rdx
+
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 9);
+
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x3d);
+
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(), view[4] == 0xe8);
+
+ memcpy(view - 3, "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0\0", 12);
+
+ // The next reloc should be a PLT32 reloc against __tls_get_addr.
+ // We can skip it.
+ this->skip_call_tls_get_addr_ = true;
+}
+