2007-08-21 H.J. Lu <hongjiu.lu@intel.com>
[deliverable/binutils-gdb.git] / bfd / elf64-x86-64.c
index 389c89a9615be70b401e24388173382b2b72c4a0..4a56d713daee7e9bcdf9f81346aff9028bcae525 100644 (file)
@@ -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;
            }
This page took 0.031128 seconds and 4 git commands to generate.