2007-08-21 H.J. Lu <hongjiu.lu@intel.com>
[deliverable/binutils-gdb.git] / bfd / elf64-x86-64.c
index 23dee168615838df336f08199ba12eb9127467f8..4a56d713daee7e9bcdf9f81346aff9028bcae525 100644 (file)
@@ -1,5 +1,5 @@
 /* X86-64 specific support for 64-bit ELF
 /* X86-64 specific support for 64-bit ELF
-   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
    Contributed by Jan Hubicka <jh@suse.cz>.
 
    Free Software Foundation, Inc.
    Contributed by Jan Hubicka <jh@suse.cz>.
 
@@ -7,7 +7,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
 
-#include "bfd.h"
 #include "sysdep.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
@@ -246,6 +247,23 @@ elf64_x86_64_reloc_type_lookup (bfd *abfd,
   return 0;
 }
 
   return 0;
 }
 
+static reloc_howto_type *
+elf64_x86_64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                               const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0;
+       i < (sizeof (x86_64_elf_howto_table)
+           / sizeof (x86_64_elf_howto_table[0]));
+       i++)
+    if (x86_64_elf_howto_table[i].name != NULL
+       && strcasecmp (x86_64_elf_howto_table[i].name, r_name) == 0)
+      return &x86_64_elf_howto_table[i];
+
+  return NULL;
+}
+
 /* Given an x86_64 ELF reloc type, fill in an arelent structure.  */
 
 static void
 /* Given an x86_64 ELF reloc type, fill in an arelent structure.  */
 
 static void
@@ -695,7 +713,8 @@ elf64_x86_64_elf_object_p (bfd *abfd)
 }
 
 static int
 }
 
 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;
 {
   if (info->shared)
     return r_type;
@@ -706,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:
     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:
        return R_X86_64_TPOFF32;
       return R_X86_64_GOTTPOFF;
     case R_X86_64_TLSLD:
@@ -767,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;
        }
 
            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:
       switch (r_type)
        {
        case R_X86_64_TLSLD:
@@ -1197,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_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:
       switch (r_type)
        {
        case R_X86_64_TLSLD:
@@ -1270,7 +1289,6 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
 {
   struct elf64_x86_64_link_hash_table *htab;
   asection *s;
 {
   struct elf64_x86_64_link_hash_table *htab;
   asection *s;
-  unsigned int power_of_two;
 
   /* If this is a function, put it in the procedure linkage table.  We
      will fill in the contents of the procedure linkage table later,
 
   /* If this is a function, put it in the procedure linkage table.  We
      will fill in the contents of the procedure linkage table later,
@@ -1388,32 +1406,9 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
       h->needs_copy = 1;
     }
 
       h->needs_copy = 1;
     }
 
-  /* We need to figure out the alignment required for this symbol.  I
-     have no idea how ELF linkers handle this. 16-bytes is the size
-     of the largest type that requires hard alignment -- long double.  */
-  /* FIXME: This is VERY ugly. Should be fixed for all architectures using
-     this construct.  */
-  power_of_two = bfd_log2 (h->size);
-  if (power_of_two > 4)
-    power_of_two = 4;
-
-  /* Apply the required alignment.  */
   s = htab->sdynbss;
   s = htab->sdynbss;
-  s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
-  if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s))
-    {
-      if (! bfd_set_section_alignment (htab->elf.dynobj, s, power_of_two))
-       return FALSE;
-    }
 
 
-  /* Define the symbol as being at this point in the section.  */
-  h->root.u.def.section = s;
-  h->root.u.def.value = s->size;
-
-  /* Increment the section size to make room for the symbol.  */
-  s->size += h->size;
-
-  return TRUE;
+  return _bfd_elf_adjust_dynamic_copy (h, s);
 }
 
 /* Allocate space in .plt, .got and associated reloc sections for
 }
 
 /* Allocate space in .plt, .got and associated reloc sections for
@@ -2062,9 +2057,6 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
 
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
 
-  if (info->relocatable)
-    return TRUE;
-
   htab = elf64_x86_64_hash_table (info);
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
   htab = elf64_x86_64_hash_table (info);
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
@@ -2120,6 +2112,21 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                                   h, sec, relocation,
                                   unresolved_reloc, warned);
        }
                                   h, sec, relocation,
                                   unresolved_reloc, warned);
        }
+
+      if (sec != NULL && elf_discarded_section (sec))
+       {
+         /* For relocs against symbols from removed linkonce sections,
+            or sections discarded by a linker script, we just want the
+            section contents zeroed.  Avoid any special processing.  */
+         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+         rel->r_info = 0;
+         rel->r_addend = 0;
+         continue;
+       }
+
+      if (info->relocatable)
+       continue;
+
       /* When generating a shared object, the relocations handled here are
         copied into the output file to be resolved at run time.  */
       switch (r_type)
       /* When generating a shared object, the relocations handled here are
         copied into the output file to be resolved at run time.  */
       switch (r_type)
@@ -2367,11 +2374,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          /* FIXME: The ABI says the linker should make sure the value is
             the same when it's zeroextended to 64 bit.  */
 
          /* FIXME: The ABI says the linker should make sure the value is
             the same when it's zeroextended to 64 bit.  */
 
-         /* r_symndx will be zero only for relocs against symbols
-            from removed linkonce sections, or sections discarded by
-            a linker script.  */
-         if (r_symndx == 0
-             || (input_section->flags & SEC_ALLOC) == 0)
+         if ((input_section->flags & SEC_ALLOC) == 0)
            break;
 
          if ((info->shared
            break;
 
          if ((info->shared
@@ -2457,9 +2460,19 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                        {
                          asection *osec;
 
                        {
                          asection *osec;
 
+                         /* We are turning this relocation into one
+                            against a section symbol.  It would be
+                            proper to subtract the symbol's value,
+                            osec->vma, from the emitted reloc addend,
+                            but ld.so expects buggy relocs.  */
                          osec = sec->output_section;
                          sindx = elf_section_data (osec)->dynindx;
                          osec = sec->output_section;
                          sindx = elf_section_data (osec)->dynindx;
-                         BFD_ASSERT (sindx > 0);
+                         if (sindx == 0)
+                           {
+                             asection *oi = htab->elf.text_index_section;
+                             sindx = elf_section_data (oi)->dynindx;
+                           }
+                         BFD_ASSERT (sindx != 0);
                        }
 
                      outrel.r_info = ELF64_R_INFO (sindx, r_type);
                        }
 
                      outrel.r_info = ELF64_R_INFO (sindx, r_type);
@@ -2489,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:
        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];
          tls_type = GOT_UNKNOWN;
          if (h == NULL && local_got_offsets)
            tls_type = elf64_x86_64_local_got_tls_type (input_bfd) [r_symndx];
@@ -2515,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 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
 
                  /* 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 */
                     Change it into:
                     movq %fs:0, %rax
                     leaq foo@tpoff(%rax), %rax */
@@ -2533,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);
                                           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);
                  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;
                }
                  rel++;
                  continue;
                }
@@ -2907,9 +2931,12 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        case R_X86_64_TLSLD:
          if (! info->shared)
            {
        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:
              /* 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);
                 We change it into:
                 .word 0x6666; .byte 0x66; movl %fs:0, %rax.  */
              BFD_ASSERT (rel->r_offset >= 3);
@@ -2923,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 (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);
              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;
            }
              rel++;
              continue;
            }
@@ -3642,6 +3677,8 @@ static const struct bfd_elf_special_section
 #define bfd_elf64_bfd_link_hash_table_create \
   elf64_x86_64_link_hash_table_create
 #define bfd_elf64_bfd_reloc_type_lookup            elf64_x86_64_reloc_type_lookup
 #define bfd_elf64_bfd_link_hash_table_create \
   elf64_x86_64_link_hash_table_create
 #define bfd_elf64_bfd_reloc_type_lookup            elf64_x86_64_reloc_type_lookup
+#define bfd_elf64_bfd_reloc_name_lookup \
+  elf64_x86_64_reloc_name_lookup
 
 #define elf_backend_adjust_dynamic_symbol   elf64_x86_64_adjust_dynamic_symbol
 #define elf_backend_check_relocs           elf64_x86_64_check_relocs
 
 #define elf_backend_adjust_dynamic_symbol   elf64_x86_64_adjust_dynamic_symbol
 #define elf_backend_check_relocs           elf64_x86_64_check_relocs
@@ -3657,6 +3694,7 @@ static const struct bfd_elf_special_section
 #define elf_backend_relocate_section       elf64_x86_64_relocate_section
 #define elf_backend_size_dynamic_sections   elf64_x86_64_size_dynamic_sections
 #define elf_backend_always_size_sections    elf64_x86_64_always_size_sections
 #define elf_backend_relocate_section       elf64_x86_64_relocate_section
 #define elf_backend_size_dynamic_sections   elf64_x86_64_size_dynamic_sections
 #define elf_backend_always_size_sections    elf64_x86_64_always_size_sections
+#define elf_backend_init_index_section     _bfd_elf_init_1_index_section
 #define elf_backend_plt_sym_val                    elf64_x86_64_plt_sym_val
 #define elf_backend_object_p               elf64_x86_64_elf_object_p
 #define bfd_elf64_mkobject                 elf64_x86_64_mkobject
 #define elf_backend_plt_sym_val                    elf64_x86_64_plt_sym_val
 #define elf_backend_object_p               elf64_x86_64_elf_object_p
 #define bfd_elf64_mkobject                 elf64_x86_64_mkobject
@@ -3694,24 +3732,11 @@ static const struct bfd_elf_special_section
 #undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME                 "elf64-x86-64-freebsd"
 
 #undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME                 "elf64-x86-64-freebsd"
 
-/* The kernel recognizes executables as valid only if they carry a
-   "FreeBSD" label in the ELF header.  So we put this label on all
-   executables and (for simplicity) also all other object files.  */
-
-static void
-elf64_x86_64_fbsd_post_process_headers (bfd * abfd,
-                                       struct bfd_link_info * link_info ATTRIBUTE_UNUSED)
-{
-  Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form.  */
-
-  i_ehdrp = elf_elfheader (abfd);
-
-  /* Put an ABI label supported by FreeBSD >= 4.1.  */
-  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
-}
+#undef ELF_OSABI
+#define        ELF_OSABI                           ELFOSABI_FREEBSD
 
 #undef  elf_backend_post_process_headers
 
 #undef  elf_backend_post_process_headers
-#define elf_backend_post_process_headers  elf64_x86_64_fbsd_post_process_headers
+#define elf_backend_post_process_headers  _bfd_elf_set_osabi
 
 #undef  elf64_bed
 #define elf64_bed elf64_x86_64_fbsd_bed
 
 #undef  elf64_bed
 #define elf64_bed elf64_x86_64_fbsd_bed
This page took 0.02815 seconds and 4 git commands to generate.