Warn relocation in readonly section in a shared object.
[binutils-gdb.git] / bfd / elf32-i386.c
index 7a426d51274efc4c62a5e0d360b64dc9f00710fa..e32ec831c72b03bb5ca4221f282e155e823de244 100644 (file)
@@ -1,6 +1,7 @@
 /* Intel 80386/80486-specific support for 32-bit ELF
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -323,7 +324,7 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 
     case BFD_RELOC_386_IRELATIVE:
       TRACE ("BFD_RELOC_386_IRELATIVE");
-      return &elf_howto_table[R_386_IRELATIVE];
+      return &elf_howto_table[R_386_IRELATIVE - R_386_tls_offset];
 
     case BFD_RELOC_VTABLE_INHERIT:
       TRACE ("BFD_RELOC_VTABLE_INHERIT");
@@ -1807,23 +1808,10 @@ elf_i386_gc_sweep_hook (bfd *abfd,
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx >= symtab_hdr->sh_info)
        {
-         struct elf_i386_link_hash_entry *eh;
-         struct elf_dyn_relocs **pp;
-         struct elf_dyn_relocs *p;
-
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
-         eh = (struct elf_i386_link_hash_entry *) h;
-
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
-           if (p->sec == sec)
-             {
-               /* Everything must go for SEC.  */
-               *pp = p->next;
-               break;
-             }
        }
       else
        {
@@ -1843,6 +1831,22 @@ elf_i386_gc_sweep_hook (bfd *abfd,
            }
        }
 
+      if (h)
+       {
+         struct elf_i386_link_hash_entry *eh;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
+
+         eh = (struct elf_i386_link_hash_entry *) h;
+         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+           if (p->sec == sec)
+             {
+               /* Everything must go for SEC.  */
+               *pp = p->next;
+               break;
+             }
+       }
+
       r_type = ELF32_R_TYPE (rel->r_info);
       if (! elf_i386_tls_transition (info, abfd, sec, NULL,
                                     symtab_hdr, sym_hashes,
@@ -1883,7 +1887,8 @@ elf_i386_gc_sweep_hook (bfd *abfd,
 
        case R_386_32:
        case R_386_PC32:
-         if (info->shared)
+         if (info->shared
+             && (h == NULL || h->type != STT_GNU_IFUNC))
            break;
          /* Fall through */
 
@@ -2379,6 +2384,10 @@ elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
+  /* Skip local IFUNC symbols. */
+  if (h->forced_local && h->type == STT_GNU_IFUNC)
+    return TRUE;
+
   eh = (struct elf_i386_link_hash_entry *) h;
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
@@ -2390,6 +2399,11 @@ elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
          info->flags |= DF_TEXTREL;
 
+         if (info->warn_shared_textrel && info->shared)
+           info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'.\n"),
+                                   p->sec->owner, h->root.root.string,
+                                   p->sec);
+
          /* Not an error, just cut short the traversal.  */
          return FALSE;
        }
@@ -2473,7 +2487,13 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                  srel = elf_section_data (p->sec)->sreloc;
                  srel->size += p->count * sizeof (Elf32_External_Rel);
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
-                   info->flags |= DF_TEXTREL;
+                   {
+                     info->flags |= DF_TEXTREL;
+                     if (info->warn_shared_textrel && info->shared)
+                       info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'.\n"),
+                                               p->sec->owner, p->sec);
+                     break;
+                   }
                }
            }
        }
@@ -2559,10 +2579,17 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
   if (htab->elf.sgotplt)
     {
+      struct elf_link_hash_entry *got;
+      got = elf_link_hash_lookup (elf_hash_table (info),
+                                 "_GLOBAL_OFFSET_TABLE_",
+                                 FALSE, FALSE, FALSE);
+
       /* Don't allocate .got.plt section if there are no GOT nor PLT
-         entries.  */
-      if ((htab->elf.sgotplt->size
-          == get_elf_backend_data (output_bfd)->got_header_size)
+         entries and there is no refeence to _GLOBAL_OFFSET_TABLE_.  */
+      if ((got == NULL
+          || !got->ref_regular_nonweak)
+         && (htab->elf.sgotplt->size
+             == get_elf_backend_data (output_bfd)->got_header_size)
          && (htab->elf.splt == NULL
              || htab->elf.splt->size == 0)
          && (htab->elf.sgot == NULL
@@ -2821,11 +2848,16 @@ static bfd_vma
 elf_i386_tpoff (struct bfd_link_info *info, bfd_vma address)
 {
   struct elf_link_hash_table *htab = elf_hash_table (info);
+  const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd);
+  bfd_vma static_tls_size;
 
   /* If tls_sec is NULL, we should have signalled an error already.  */
   if (htab->tls_sec == NULL)
     return 0;
-  return htab->tls_size + htab->tls_sec->vma - address;
+
+  /* Consider special static TLS alignment requirements.  */
+  static_tls_size = BFD_ALIGN (htab->tls_size, bed->static_tls_alignment);
+  return static_tls_size + htab->tls_sec->vma - address;
 }
 
 /* Relocate an i386 ELF section.  */
@@ -3112,7 +3144,7 @@ elf_i386_relocate_section (bfd *output_bfd,
                     internal symbol, we have updated addend.  */
                  continue;
                }
-
+             /* FALLTHROUGH */
            case R_386_PC32:
            case R_386_PLT32:
              goto do_relocation;
@@ -3435,7 +3467,11 @@ elf_i386_relocate_section (bfd *output_bfd,
 
              sreloc = elf_section_data (input_section)->sreloc;
 
-             BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
+             if (sreloc == NULL || sreloc->contents == NULL)
+               {
+                 r = bfd_reloc_notsupported;
+                 goto check_relocation_error;
+               }
 
              loc = sreloc->contents;
              loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel);
@@ -4009,7 +4045,7 @@ elf_i386_relocate_section (bfd *output_bfd,
          break;
 
        case R_386_TLS_LDO_32:
-         if (info->shared || (input_section->flags & SEC_CODE) == 0)
+         if (!info->executable || (input_section->flags & SEC_CODE) == 0)
            relocation -= elf_i386_dtpoff_base (info);
          else
            /* When converting LDO to LE, we must negate.  */
@@ -4080,6 +4116,7 @@ do_relocation:
                                    contents, rel->r_offset,
                                    relocation, 0);
 
+check_relocation_error:
       if (r != bfd_reloc_ok)
        {
          const char *name;
@@ -4167,7 +4204,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
          || plt == NULL
          || gotplt == NULL
          || relplt == NULL)
-       abort ();
+       return FALSE;
 
       /* Get the index in the procedure linkage table which
         corresponds to this symbol.  This is the index of this symbol
@@ -4683,8 +4720,9 @@ elf_i386_add_symbol_hook (bfd * abfd,
                          bfd_vma * valp ATTRIBUTE_UNUSED)
 {
   if ((abfd->flags & DYNAMIC) == 0
-      && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
-    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+         || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
 
   return TRUE;
 }
@@ -4788,6 +4826,11 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
 #undef elf32_bed
 #define        elf32_bed                       elf32_i386_sol2_bed
 
+/* The 32-bit static TLS arena size is rounded to the nearest 8-byte
+   boundary.  */
+#undef elf_backend_static_tls_alignment
+#define elf_backend_static_tls_alignment 8
+
 /* The Solaris 2 ABI requires a plt symbol on all platforms.
 
    Cf. Linker and Libraries Guide, Ch. 2, Link-Editor, Generating the Output
@@ -4841,6 +4884,7 @@ elf_i386_vxworks_link_hash_table_create (bfd *abfd)
 #undef elf_backend_final_write_processing
 #define elf_backend_final_write_processing \
   elf_vxworks_final_write_processing
+#undef elf_backend_static_tls_alignment
 
 /* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so
    define it.  */