+ {
+ case R_X86_64_TLSGD:
+ case R_X86_64_TLSLD:
+ if ((rel + 1) >= relend)
+ return FALSE;
+
+ if (r_type == R_X86_64_TLSGD)
+ {
+ /* Check transition from GD access model. Only
+ .byte 0x66; leaq foo@tlsgd(%rip), %rdi
+ .word 0x6666; rex64; call __tls_get_addr
+ can transit to different access model. */
+
+ static x86_64_opcode32 leaq = { { 0x66, 0x48, 0x8d, 0x3d } },
+ call = { { 0x66, 0x66, 0x48, 0xe8 } };
+ if (offset < 4
+ || (offset + 12) > sec->size
+ || bfd_get_32 (abfd, contents + offset - 4) != leaq.i
+ || bfd_get_32 (abfd, contents + offset + 4) != call.i)
+ return FALSE;
+ }
+ else
+ {
+ /* Check transition from LD access model. Only
+ leaq foo@tlsld(%rip), %rdi;
+ call __tls_get_addr
+ can transit to different access model. */
+
+ static x86_64_opcode32 ld = { { 0x48, 0x8d, 0x3d, 0xe8 } };
+ x86_64_opcode32 op;
+
+ if (offset < 3 || (offset + 9) > sec->size)
+ return FALSE;
+
+ op.i = bfd_get_32 (abfd, contents + offset - 3);
+ op.c[3] = bfd_get_8 (abfd, contents + offset + 4);
+ if (op.i != ld.i)
+ return FALSE;
+ }
+
+ r_symndx = ELF64_R_SYM (rel[1].r_info);
+ if (r_symndx < symtab_hdr->sh_info)
+ return FALSE;
+
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ /* Use strncmp to check __tls_get_addr since __tls_get_addr
+ may be versioned. */
+ return (h != NULL
+ && h->root.root.string != NULL
+ && (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32
+ || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32)
+ && (strncmp (h->root.root.string,
+ "__tls_get_addr", 14) == 0));
+
+ case R_X86_64_GOTTPOFF:
+ /* Check transition from IE access model:
+ movq foo@gottpoff(%rip), %reg
+ addq foo@gottpoff(%rip), %reg
+ */
+
+ if (offset < 3 || (offset + 4) > sec->size)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 3);
+ if (val != 0x48 && val != 0x4c)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 2);
+ if (val != 0x8b && val != 0x03)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ return (val & 0xc7) == 5;
+
+ case R_X86_64_GOTPC32_TLSDESC:
+ /* Check transition from GDesc access model:
+ leaq x@tlsdesc(%rip), %rax
+
+ Make sure it's a leaq adding rip to a 32-bit offset
+ into any register, although it's probably almost always
+ going to be rax. */
+
+ if (offset < 3 || (offset + 4) > sec->size)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 3);
+ if ((val & 0xfb) != 0x48)
+ return FALSE;
+
+ if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ return (val & 0xc7) == 0x05;
+
+ case R_X86_64_TLSDESC_CALL:
+ /* Check transition from GDesc access model:
+ call *x@tlsdesc(%rax)
+ */
+ if (offset + 2 <= sec->size)
+ {
+ /* Make sure that it's a call *x@tlsdesc(%rax). */
+ static x86_64_opcode16 call = { { 0xff, 0x10 } };
+ return bfd_get_16 (abfd, contents + offset) == call.i;
+ }
+
+ return FALSE;
+
+ default:
+ abort ();
+ }
+}
+
+/* Return TRUE if the TLS access transition is OK or no transition
+ will be performed. Update R_TYPE if there is a transition. */
+
+static bfd_boolean
+elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
+ asection *sec, bfd_byte *contents,
+ Elf_Internal_Shdr *symtab_hdr,
+ struct elf_link_hash_entry **sym_hashes,
+ unsigned int *r_type, int tls_type,
+ const Elf_Internal_Rela *rel,
+ const Elf_Internal_Rela *relend,
+ struct elf_link_hash_entry *h)
+{
+ unsigned int from_type = *r_type;
+ unsigned int to_type = from_type;
+ bfd_boolean check = TRUE;
+
+ switch (from_type)