]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/elf32-i386.c
bfd/
[thirdparty/binutils-gdb.git] / bfd / elf32-i386.c
index 6b51f38b4c4ad7ffc9400023697dfbb1697e793d..35cb7c62fcd54117c897ea91f9832300593e5e0a 100644 (file)
@@ -1,6 +1,6 @@
 /* Intel 80386/80486-specific support for 32-bit ELF
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -18,8 +18,8 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
-#include "bfd.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
@@ -330,6 +330,20 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return 0;
 }
 
+static reloc_howto_type *
+elf_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                           const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++)
+    if (elf_howto_table[i].name != NULL
+       && strcasecmp (elf_howto_table[i].name, r_name) == 0)
+      return &elf_howto_table[i];
+
+  return NULL;
+}
+
 static void
 elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
                            arelent *cache_ptr,
@@ -622,11 +636,14 @@ struct elf_i386_obj_tdata
 static bfd_boolean
 elf_i386_mkobject (bfd *abfd)
 {
-  bfd_size_type amt = sizeof (struct elf_i386_obj_tdata);
-  abfd->tdata.any = bfd_zalloc (abfd, amt);
   if (abfd->tdata.any == NULL)
-    return FALSE;
-  return TRUE;
+    {
+      bfd_size_type amt = sizeof (struct elf_i386_obj_tdata);
+      abfd->tdata.any = bfd_zalloc (abfd, amt);
+      if (abfd->tdata.any == NULL)
+       return FALSE;
+    }
+  return bfd_elf_mkobject (abfd);
 }
 
 /* i386 ELF linker hash table.  */
@@ -721,7 +738,8 @@ elf_i386_link_hash_table_create (bfd *abfd)
   if (ret == NULL)
     return NULL;
 
-  if (! _bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc))
+  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc,
+                                     sizeof (struct elf_i386_link_hash_entry)))
     {
       free (ret);
       return NULL;
@@ -782,9 +800,6 @@ static bfd_boolean
 elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
 {
   struct elf_i386_link_hash_table *htab;
-  asection * s;
-  int flags;
-  const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
 
   htab = elf_i386_hash_table (info);
   if (!htab->sgot && !create_got_section (dynobj, info))
@@ -803,17 +818,9 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
       || (!info->shared && !htab->srelbss))
     abort ();
 
-  if (htab->is_vxworks && !info->shared)
-    {
-      s = bfd_make_section (dynobj, ".rel.plt.unloaded");
-      flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_READONLY
-             | SEC_LINKER_CREATED);
-      if (s == NULL
-        || ! bfd_set_section_flags (dynobj, s, flags)
-        || ! bfd_set_section_alignment (dynobj, s, bed->s->log_file_align))
-       return FALSE;
-      htab->srelplt2 = s;
-    }
+  if (htab->is_vxworks
+      && !elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2))
+    return FALSE;
 
   return TRUE;
 }
@@ -1157,7 +1164,7 @@ elf_i386_check_relocs (bfd *abfd,
               && (sec->flags & SEC_ALLOC) != 0
               && (r_type != R_386_PC32
                   || (h != NULL
-                      && (! info->symbolic
+                      && (! SYMBOLIC_BIND (info, h)
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
              || (ELIMINATE_COPY_RELOCS
@@ -1184,7 +1191,7 @@ elf_i386_check_relocs (bfd *abfd,
                  if (name == NULL)
                    return FALSE;
 
-                 if (strncmp (name, ".rel", 4) != 0
+                 if (! CONST_STRNEQ (name, ".rel")
                      || strcmp (bfd_get_section_name (abfd, sec),
                                 name + 4) != 0)
                    {
@@ -1286,38 +1293,20 @@ elf_i386_check_relocs (bfd *abfd,
 
 static asection *
 elf_i386_gc_mark_hook (asection *sec,
-                      struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                      struct bfd_link_info *info,
                       Elf_Internal_Rela *rel,
                       struct elf_link_hash_entry *h,
                       Elf_Internal_Sym *sym)
 {
   if (h != NULL)
-    {
-      switch (ELF32_R_TYPE (rel->r_info))
-       {
-       case R_386_GNU_VTINHERIT:
-       case R_386_GNU_VTENTRY:
-         break;
-
-       default:
-         switch (h->root.type)
-           {
-           case bfd_link_hash_defined:
-           case bfd_link_hash_defweak:
-             return h->root.u.def.section;
-
-           case bfd_link_hash_common:
-             return h->root.u.c.p->section;
-
-           default:
-             break;
-           }
-       }
-    }
-  else
-    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
-
-  return NULL;
+    switch (ELF32_R_TYPE (rel->r_info))
+      {
+      case R_386_GNU_VTINHERIT:
+      case R_386_GNU_VTENTRY:
+       return NULL;
+      }
+
+  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
 }
 
 /* Update the got entry reference counts for the section being removed.  */
@@ -2000,21 +1989,6 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   else
     htab->tls_ldm_got.offset = -1;
 
-  if (htab->is_vxworks)
-    {
-      /* Mark the GOT and PLT symbols as having relocations; they might
-        not, but we won't know for sure until we build the GOT in
-        finish_dynamic_symbol.  */
-      if (htab->elf.hgot)
-       htab->elf.hgot->indx = -2;
-      if (htab->elf.hplt)
-       {
-         htab->elf.hplt->indx = -2;
-         if (htab->splt->flags & SEC_CODE)
-           htab->elf.hplt->type = STT_FUNC;
-       }
-    }
-
   /* Allocate global sym .plt and .got entries, and space for global
      sym dynamic relocs.  */
   elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
@@ -2051,7 +2025,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
          if (htab->elf.hplt != NULL)
            strip_section = FALSE;
        }
-      else if (strncmp (bfd_get_section_name (dynobj, s), ".rel", 4) == 0)
+      else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rel"))
        {
          if (s->size != 0 && s != htab->srelplt && s != htab->srelplt2)
            relocs = TRUE;
@@ -2304,51 +2278,6 @@ elf_i386_relocate_section (bfd *output_bfd,
       howto = elf_howto_table + indx;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
-
-      if (info->relocatable)
-       {
-         bfd_vma val;
-         bfd_byte *where;
-
-         /* This is a relocatable link.  We don't have to change
-            anything, unless the reloc is against a section symbol,
-            in which case we have to adjust according to where the
-            section symbol winds up in the output section.  */
-         if (r_symndx >= symtab_hdr->sh_info)
-           continue;
-
-         sym = local_syms + r_symndx;
-         if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
-           continue;
-
-         sec = local_sections[r_symndx];
-         val = sec->output_offset;
-         if (val == 0)
-           continue;
-
-         where = contents + rel->r_offset;
-         switch (howto->size)
-           {
-             /* FIXME: overflow checks.  */
-           case 0:
-             val += bfd_get_8 (input_bfd, where);
-             bfd_put_8 (input_bfd, val, where);
-             break;
-           case 1:
-             val += bfd_get_16 (input_bfd, where);
-             bfd_put_16 (input_bfd, val, where);
-             break;
-           case 2:
-             val += bfd_get_32 (input_bfd, where);
-             bfd_put_32 (input_bfd, val, where);
-             break;
-           default:
-             abort ();
-           }
-         continue;
-       }
-
-      /* This is a final link.  */
       h = NULL;
       sym = NULL;
       sec = NULL;
@@ -2360,10 +2289,12 @@ elf_i386_relocate_section (bfd *output_bfd,
          relocation = (sec->output_section->vma
                        + sec->output_offset
                        + sym->st_value);
-         if ((sec->flags & SEC_MERGE)
-             && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+
+         if (ELF_ST_TYPE (sym->st_info) == STT_SECTION
+             && ((sec->flags & SEC_MERGE) != 0
+                 || (info->relocatable
+                     && sec->output_offset != 0)))
            {
-             asection *msec;
              bfd_vma addend;
              bfd_byte *where = contents + rel->r_offset;
 
@@ -2397,10 +2328,16 @@ elf_i386_relocate_section (bfd *output_bfd,
                  abort ();
                }
 
-             msec = sec;
-             addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
-             addend -= relocation;
-             addend += msec->output_section->vma + msec->output_offset;
+             if (info->relocatable)
+               addend += sec->output_offset;
+             else
+               {
+                 asection *msec = sec;
+                 addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec,
+                                                  addend);
+                 addend -= relocation;
+                 addend += msec->output_section->vma + msec->output_offset;
+               }
 
              switch (howto->size)
                {
@@ -2433,21 +2370,20 @@ elf_i386_relocate_section (bfd *output_bfd,
                                   unresolved_reloc, warned);
        }
 
-      if (r_symndx == 0)
+      if (sec != NULL && elf_discarded_section (sec))
        {
-       /* r_symndx will be zero only for relocs against symbols from
-          removed linkonce sections, or sections discarded by a linker
-          script.  For these relocs, we just want the section contents
-          zeroed.  Avoid any special processing in the switch below.  */
-         r_type = R_386_NONE;
-
-         relocation = 0;
-         if (howto->pc_relative)
-           relocation = (input_section->output_section->vma
-                         + input_section->output_offset
-                         + rel->r_offset);
+         /* 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;
+
       switch (r_type)
        {
        case R_386_GOT32:
@@ -2651,7 +2587,7 @@ elf_i386_relocate_section (bfd *output_bfd,
                       && h->dynindx != -1
                       && (r_type == R_386_PC32
                           || !info->shared
-                          || !info->symbolic
+                          || !SYMBOLIC_BIND (info, h)
                           || !h->def_regular))
                outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
              else
@@ -2843,8 +2779,9 @@ elf_i386_relocate_section (bfd *output_bfd,
                  val = bfd_get_8 (input_bfd, contents + roff + 1);
                  BFD_ASSERT (val == 0x10);
 
-                 /* Now modify the instruction as appropriate.  */
-                 bfd_put_8 (output_bfd, 0x90, contents + roff);
+                 /* Now modify the instruction as appropriate.  Use
+                    xchg %ax,%ax instead of 2 nops.  */
+                 bfd_put_8 (output_bfd, 0x66, contents + roff);
                  bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
                  continue;
                }
@@ -3164,12 +3101,8 @@ elf_i386_relocate_section (bfd *output_bfd,
                 subl $foo@gottpoff(%reg), %eax
                 into:
                 addl $foo@gotntpoff(%reg), %eax.  */
-             if (r_type == R_386_TLS_GOTIE)
-               {
-                 contents[roff + 6] = 0x03;
-                 if (tls_type == GOT_TLS_IE_BOTH)
-                   off += 4;
-               }
+             if (tls_type == GOT_TLS_IE_POS)
+               contents[roff + 6] = 0x03;
              bfd_put_32 (output_bfd,
                          htab->sgot->output_section->vma
                          + htab->sgot->output_offset + off
@@ -3253,8 +3186,8 @@ elf_i386_relocate_section (bfd *output_bfd,
              /* Now modify the instruction as appropriate.  */
              if (tls_type != GOT_TLS_IE_NEG)
                {
-                 /* nop; nop */
-                 bfd_put_8 (output_bfd, 0x90, contents + roff);
+                 /* xchg %ax,%ax */
+                 bfd_put_8 (output_bfd, 0x66, contents + roff);
                  bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
                }
              else
@@ -3864,6 +3797,18 @@ elf_i386_plt_sym_val (bfd_vma i, const asection *plt,
   return plt->vma + (i + 1) * PLT_ENTRY_SIZE;
 }
 
+/* Return TRUE if symbol should be hashed in the `.gnu.hash' section.  */
+
+static bfd_boolean
+elf_i386_hash_symbol (struct elf_link_hash_entry *h)
+{
+  if (h->plt.offset != (bfd_vma) -1
+      && !h->def_regular
+      && !h->pointer_equality_needed)
+    return FALSE;
+
+  return _bfd_elf_hash_symbol (h);
+}
 
 #define TARGET_LITTLE_SYM              bfd_elf32_i386_vec
 #define TARGET_LITTLE_NAME             "elf32-i386"
@@ -3887,6 +3832,7 @@ elf_i386_plt_sym_val (bfd_vma i, const asection *plt,
 #define bfd_elf32_bfd_is_local_label_name     elf_i386_is_local_label_name
 #define bfd_elf32_bfd_link_hash_table_create  elf_i386_link_hash_table_create
 #define bfd_elf32_bfd_reloc_type_lookup              elf_i386_reloc_type_lookup
+#define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup
 
 #define elf_backend_adjust_dynamic_symbol     elf_i386_adjust_dynamic_symbol
 #define elf_backend_check_relocs             elf_i386_check_relocs
@@ -3903,7 +3849,10 @@ elf_i386_plt_sym_val (bfd_vma i, const asection *plt,
 #define elf_backend_relocate_section         elf_i386_relocate_section
 #define elf_backend_size_dynamic_sections     elf_i386_size_dynamic_sections
 #define elf_backend_always_size_sections      elf_i386_always_size_sections
+#define elf_backend_omit_section_dynsym \
+  ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
 #define elf_backend_plt_sym_val                      elf_i386_plt_sym_val
+#define elf_backend_hash_symbol                      elf_i386_hash_symbol
 
 #include "elf32-target.h"
 
@@ -3913,6 +3862,8 @@ elf_i386_plt_sym_val (bfd_vma i, const asection *plt,
 #define        TARGET_LITTLE_SYM               bfd_elf32_i386_freebsd_vec
 #undef TARGET_LITTLE_NAME
 #define        TARGET_LITTLE_NAME              "elf32-i386-freebsd"
+#undef ELF_OSABI
+#define        ELF_OSABI                       ELFOSABI_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
@@ -3927,7 +3878,7 @@ elf_i386_post_process_headers (bfd *abfd,
   i_ehdrp = elf_elfheader (abfd);
 
   /* Put an ABI label supported by FreeBSD >= 4.1.  */
-  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
+  i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
 #ifdef OLD_FREEBSD_ABI_LABEL
   /* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard.  */
   memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8);
@@ -3947,7 +3898,7 @@ elf_i386_post_process_headers (bfd *abfd,
 #define TARGET_LITTLE_SYM              bfd_elf32_i386_vxworks_vec
 #undef TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME             "elf32-i386-vxworks"
-
+#undef ELF_OSABI
 
 /* Like elf_i386_link_hash_table_create but with tweaks for VxWorks.  */