X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf64-x86-64.c;h=4a56d713daee7e9bcdf9f81346aff9028bcae525;hb=2f3bf80a30d2c892f60087a246e8b4b4b33498d2;hp=389c89a9615be70b401e24388173382b2b72c4a0;hpb=cd123cb70c845b890eed231a84e6e84c92c2ef92;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 389c89a961..4a56d713da 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -713,7 +713,8 @@ elf64_x86_64_elf_object_p (bfd *abfd) } static int -elf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type, int is_local) +elf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type, + struct elf_link_hash_entry *h) { if (info->shared) return r_type; @@ -724,7 +725,7 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type, int is_loca case R_X86_64_GOTPC32_TLSDESC: case R_X86_64_TLSDESC_CALL: case R_X86_64_GOTTPOFF: - if (is_local) + if (h == NULL) return R_X86_64_TPOFF32; return R_X86_64_GOTTPOFF; case R_X86_64_TLSLD: @@ -785,7 +786,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, h = (struct elf_link_hash_entry *) h->root.u.i.link; } - r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL); + r_type = elf64_x86_64_tls_transition (info, r_type, h); switch (r_type) { case R_X86_64_TLSLD: @@ -1215,7 +1216,7 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, } r_type = ELF64_R_TYPE (rel->r_info); - r_type = elf64_x86_64_tls_transition (info, r_type, h != NULL); + r_type = elf64_x86_64_tls_transition (info, r_type, h); switch (r_type) { case R_X86_64_TLSLD: @@ -2501,7 +2502,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, case R_X86_64_GOTPC32_TLSDESC: case R_X86_64_TLSDESC_CALL: case R_X86_64_GOTTPOFF: - r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL); + r_type = elf64_x86_64_tls_transition (info, r_type, h); tls_type = GOT_UNKNOWN; if (h == NULL && local_got_offsets) tls_type = elf64_x86_64_local_got_tls_type (input_bfd) [r_symndx]; @@ -2527,10 +2528,12 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, unsigned int i; static unsigned char tlsgd[8] = { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 }; + unsigned long tls_r_symndx; + struct elf_link_hash_entry *tls_h; /* GD->LE transition. .byte 0x66; leaq foo@tlsgd(%rip), %rdi - .word 0x6666; rex64; call __tls_get_addr@plt + .word 0x6666; rex64; call __tls_get_addr Change it into: movq %fs:0, %rax leaq foo@tpoff(%rax), %rax */ @@ -2545,13 +2548,22 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, contents + rel->r_offset + 4 + i) == tlsgd[i+4]); BFD_ASSERT (rel + 1 < relend); - BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32); + tls_r_symndx = ELF64_R_SYM (rel[1].r_info); + BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info); + tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info]; + BFD_ASSERT (tls_h != NULL + && tls_h->root.root.string != NULL + && strcmp (tls_h->root.root.string, + "__tls_get_addr") == 0); + BFD_ASSERT ((! info->shared + && ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32) + || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32); memcpy (contents + rel->r_offset - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", 16); bfd_put_32 (output_bfd, tpoff (info, relocation), contents + rel->r_offset + 8); - /* Skip R_X86_64_PLT32. */ + /* Skip R_X86_64_PC32/R_X86_64_PLT32. */ rel++; continue; } @@ -2919,9 +2931,12 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, case R_X86_64_TLSLD: if (! info->shared) { + unsigned long tls_r_symndx; + struct elf_link_hash_entry *tls_h; + /* LD->LE transition: Ensure it is: - leaq foo@tlsld(%rip), %rdi; call __tls_get_addr@plt. + leaq foo@tlsld(%rip), %rdi; call __tls_get_addr. We change it into: .word 0x6666; .byte 0x66; movl %fs:0, %rax. */ BFD_ASSERT (rel->r_offset >= 3); @@ -2935,10 +2950,18 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4) == 0xe8); BFD_ASSERT (rel + 1 < relend); - BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32); + tls_r_symndx = ELF64_R_SYM (rel[1].r_info); + BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info); + tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info]; + BFD_ASSERT (tls_h != NULL + && tls_h->root.root.string != NULL + && strcmp (tls_h->root.root.string, + "__tls_get_addr") == 0); + BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32 + || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32); memcpy (contents + rel->r_offset - 3, "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12); - /* Skip R_X86_64_PLT32. */ + /* Skip R_X86_64_PC32/R_X86_64_PLT32. */ rel++; continue; }