* elf-m10300.c (_bfd_mn10300_elf_adjust_dynamic_symbol): Don't error
[platform/upstream/binutils.git] / bfd / elf64-x86-64.c
index 238c7bd..88c47f9 100644 (file)
@@ -1,6 +1,6 @@
 /* X86-64 specific support for ELF
    Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010, 2011
+   2010, 2011, 2012
    Free Software Foundation, Inc.
    Contributed by Jan Hubicka <jh@suse.cz>.
 
@@ -420,8 +420,6 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz,
                            int note_type, ...)
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  const void *p;
-  int size;
   va_list ap;
   const char *fname, *psargs;
   long pid;
@@ -445,8 +443,8 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz,
          memset (&data, 0, sizeof (data));
          strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
          strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
-         p = (const void *) &data;
-         size = sizeof (data);
+         return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type,
+                                    &data, sizeof (data));
        }
       else
        {
@@ -454,10 +452,10 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz,
          memset (&data, 0, sizeof (data));
          strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
          strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
-         p = (const void *) &data;
-         size = sizeof (data);
+         return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type,
+                                    &data, sizeof (data));
        }
-      break;
+      /* NOTREACHED */
 
     case NT_PRSTATUS:
       va_start (ap, note_type);
@@ -475,8 +473,8 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz,
              prstat.pr_pid = pid;
              prstat.pr_cursig = cursig;
              memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
-             p = (const void *) &prstat;
-             size = sizeof (prstat);
+             return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type,
+                                        &prstat, sizeof (prstat));
            }
          else
            {
@@ -485,8 +483,8 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz,
              prstat.pr_pid = pid;
              prstat.pr_cursig = cursig;
              memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
-             p = (const void *) &prstat;
-             size = sizeof (prstat);
+             return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type,
+                                        &prstat, sizeof (prstat));
            }
        }
       else
@@ -496,14 +494,11 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz,
          prstat.pr_pid = pid;
          prstat.pr_cursig = cursig;
          memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
-         p = (const void *) &prstat;
-         size = sizeof (prstat);
+         return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type,
+                                    &prstat, sizeof (prstat));
        }
-      break;
     }
-
-  return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type, p,
-                            size);
+  /* NOTREACHED */
 }
 #endif
 \f
@@ -513,7 +508,7 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz,
    section.  */
 
 #define ELF64_DYNAMIC_INTERPRETER "/lib/ld64.so.1"
-#define ELF32_DYNAMIC_INTERPRETER "/lib/ld32.so.1"
+#define ELF32_DYNAMIC_INTERPRETER "/lib/ldx32.so.1"
 
 /* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
    copying dynamic variables from a shared lib into an app's dynbss
@@ -698,6 +693,11 @@ struct elf_x86_64_link_hash_table
   /* The offset into sgot of the GOT entry used by the PLT entry
      above.  */
   bfd_vma tlsdesc_got;
+
+  /* The index of the next R_X86_64_JUMP_SLOT entry in .rela.plt.  */
+  bfd_vma next_jump_slot_index;
+  /* The index of the next R_X86_64_IRELATIVE entry in .rela.plt.  */
+  bfd_vma next_irelative_index;
 };
 
 /* Get the x86-64 ELF linker hash table from a link_info structure.  */
@@ -839,6 +839,8 @@ elf_x86_64_link_hash_table_create (bfd *abfd)
   ret->tls_ld_got.refcount = 0;
   ret->sgotplt_jump_table_size = 0;
   ret->tls_module_base = NULL;
+  ret->next_jump_slot_index = 0; 
+  ret->next_irelative_index = 0;
 
   if (ABI_64_P (abfd))
     {
@@ -1007,20 +1009,6 @@ elf64_x86_64_elf_object_p (bfd *abfd)
   return TRUE;
 }
 
-typedef union
-  {
-    unsigned char c[2];
-    uint16_t i;
-  }
-x86_64_opcode16;
-
-typedef union
-  {
-    unsigned char c[4];
-    uint32_t i;
-  }
-x86_64_opcode32;
-
 /* Return TRUE if the TLS access code sequence support transition
    from R_TYPE.  */
 
@@ -1076,24 +1064,23 @@ elf_x86_64_check_tls_transition (bfd *abfd,
                .word 0x6666; rex64; call __tls_get_addr
             can transit to different access model.  */
 
-         static x86_64_opcode32 call = { { 0x66, 0x66, 0x48, 0xe8 } };
+         static const unsigned char call[] = { 0x66, 0x66, 0x48, 0xe8 };
+         static const unsigned char leaq[] = { 0x66, 0x48, 0x8d, 0x3d };
+
          if ((offset + 12) > sec->size
-             || bfd_get_32 (abfd, contents + offset + 4) != call.i)
+             || memcmp (contents + offset + 4, call, 4) != 0)
            return FALSE;
 
          if (ABI_64_P (abfd))
            {
-             static x86_64_opcode32 leaq = { { 0x66, 0x48, 0x8d, 0x3d } };
              if (offset < 4
-                 || bfd_get_32 (abfd, contents + offset - 4) != leaq.i)
+                 || memcmp (contents + offset - 4, leaq, 4) != 0)
                return FALSE;
            }
          else
            {
-             static x86_64_opcode16 lea = { { 0x8d, 0x3d } };
              if (offset < 3
-                 || bfd_get_8 (abfd, contents + offset - 3) != 0x48
-                 || bfd_get_16 (abfd, contents + offset - 2) != lea.i)
+                 || memcmp (contents + offset - 3, leaq + 1, 3) != 0)
                return FALSE;
            }
        }
@@ -1104,15 +1091,13 @@ elf_x86_64_check_tls_transition (bfd *abfd,
                call __tls_get_addr
             can transit to different access model.  */
 
-         static x86_64_opcode32 ld = { { 0x48, 0x8d, 0x3d, 0xe8 } };
-         x86_64_opcode32 op;
+         static const unsigned char lea[] = { 0x48, 0x8d, 0x3d };
 
          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)
+         if (memcmp (contents + offset - 3, lea, 3) != 0
+             || 0xe8 != *(contents + offset + 4))
            return FALSE;
        }
 
@@ -1191,8 +1176,8 @@ elf_x86_64_check_tls_transition (bfd *abfd,
       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;
+         static const unsigned char call[] = { 0xff, 0x10 };
+         return memcmp (contents + offset, call, 2) == 0;
        }
 
       return FALSE;
@@ -2181,13 +2166,6 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
        }
     }
 
-  if (h->size == 0)
-    {
-      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
-                            h->root.root.string);
-      return TRUE;
-    }
-
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.         There will be
      an entry for this symbol in the .dynsym section.  The dynamic
@@ -2205,7 +2183,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
   /* We must generate a R_X86_64_COPY reloc to tell the dynamic linker
      to copy the initial value out of the dynamic object and into the
      runtime process image.  */
-  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
     {
       const struct elf_backend_data *bed;
       bed = get_elf_backend_data (info->output_bfd);
@@ -2684,10 +2662,18 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
      incremented.  However, when we reserve space for TLS descriptors,
      it's not incremented, so in order to compute the space reserved
      for them, it suffices to multiply the reloc count by the jump
-     slot size.  */
+     slot size.
+
+     PR ld/13302: We start next_irelative_index at the end of .rela.plt
+     so that R_X86_64_IRELATIVE entries come last.  */
   if (htab->elf.srelplt)
-    htab->sgotplt_jump_table_size
-      = elf_x86_64_compute_jump_table_size (htab);
+    {
+      htab->sgotplt_jump_table_size
+       = elf_x86_64_compute_jump_table_size (htab);
+      htab->next_irelative_index = htab->elf.srelplt->reloc_count - 1;
+    }
+  else if (htab->elf.irelplt)
+    htab->next_irelative_index = htab->elf.irelplt->reloc_count - 1;
 
   if (htab->tlsdesc_plt)
     {
@@ -3158,7 +3144,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                }
 
              /* Generate dynamic relcoation only when there is a
-                non-GOF reference in a shared object.  */
+                non-GOT reference in a shared object.  */
              if (info->shared && h->non_got_ref)
                {
                  Elf_Internal_Rela outrel;
@@ -3477,7 +3463,6 @@ elf_x86_64_relocate_section (bfd *output_bfd,
        case R_X86_64_PC16:
        case R_X86_64_PC32:
          if (info->shared
-             && ABI_64_P (output_bfd)
              && (input_section->flags & SEC_ALLOC) != 0
              && (input_section->flags & SEC_READONLY) != 0
              && h != NULL)
@@ -4103,7 +4088,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
         not process them.  */
       if (unresolved_reloc
          && !((input_section->flags & SEC_DEBUGGING) != 0
-              && h->def_dynamic))
+              && h->def_dynamic)
+         && _bfd_elf_section_offset (output_bfd, info, input_section,
+                                     rel->r_offset) != (bfd_vma) -1)
        (*_bfd_error_handler)
          (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
           input_bfd,
@@ -4220,13 +4207,13 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
 
       if (plt == htab->elf.splt)
        {
-         plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
-         got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
+         got_offset = h->plt.offset / PLT_ENTRY_SIZE - 1;
+         got_offset = (got_offset + 3) * GOT_ENTRY_SIZE;
        }
       else
        {
-         plt_index = h->plt.offset / PLT_ENTRY_SIZE;
-         got_offset = plt_index * GOT_ENTRY_SIZE;
+         got_offset = h->plt.offset / PLT_ENTRY_SIZE;
+         got_offset = got_offset * GOT_ENTRY_SIZE;
        }
 
       /* Fill in the entry in the procedure linkage table.  */
@@ -4248,17 +4235,6 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
                       - 6),
                  plt->contents + h->plt.offset + 2);
 
-      /* Don't fill PLT entry for static executables.  */
-      if (plt == htab->elf.splt)
-       {
-         /* Put relocation index.  */
-         bfd_put_32 (output_bfd, plt_index,
-                     plt->contents + h->plt.offset + 7);
-         /* Put offset for jmp .PLT0.  */
-         bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
-                     plt->contents + h->plt.offset + 12);
-       }
-
       /* Fill in the entry in the global offset table, initially this
         points to the pushq instruction in the PLT which is at offset 6.  */
       bfd_put_64 (output_bfd, (plt->output_section->vma
@@ -4282,11 +4258,25 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
          rela.r_addend = (h->root.u.def.value
                           + h->root.u.def.section->output_section->vma
                           + h->root.u.def.section->output_offset);
+         /* R_X86_64_IRELATIVE comes last.  */
+         plt_index = htab->next_irelative_index--;
        }
       else
        {
          rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT);
          rela.r_addend = 0;
+         plt_index = htab->next_jump_slot_index++;
+       }
+
+      /* Don't fill PLT entry for static executables.  */
+      if (plt == htab->elf.splt)
+       {
+         /* Put relocation index.  */
+         bfd_put_32 (output_bfd, plt_index,
+                     plt->contents + h->plt.offset + 7);
+         /* Put offset for jmp .PLT0.  */
+         bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
+                     plt->contents + h->plt.offset + 12);
        }
 
       bed = get_elf_backend_data (output_bfd);