2002-04-04 Daniel Jacobowitz <drow@mvista.com>
[deliverable/binutils-gdb.git] / bfd / elf32-i386.c
index 211a19cb081ac283b2c2c9365b185cdad11341d7..7165e84f50b99b1d64dff3a84e1efcd781a68e2f 100644 (file)
@@ -1,5 +1,5 @@
 /* Intel 80386/80486-specific support for 32-bit ELF
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -362,7 +362,7 @@ elf_i386_grok_psinfo (abfd, note)
       default:
        return false;
 
-      case 128:                /* Linux/MIPS elf_prpsinfo */
+      case 124:                /* Linux/i386 elf_prpsinfo */
        elf_tdata (abfd)->core_program
         = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
        elf_tdata (abfd)->core_command
@@ -497,6 +497,9 @@ struct elf_i386_link_hash_table
   asection *srelplt;
   asection *sdynbss;
   asection *srelbss;
+
+  /* Small local sym to section mapping cache.  */
+  struct sym_sec_cache sym_sec;
 };
 
 /* Get the i386 ELF linker hash table from a link_info structure.  */
@@ -544,13 +547,13 @@ elf_i386_link_hash_table_create (abfd)
   struct elf_i386_link_hash_table *ret;
   bfd_size_type amt = sizeof (struct elf_i386_link_hash_table);
 
-  ret = (struct elf_i386_link_hash_table *) bfd_alloc (abfd, amt);
+  ret = (struct elf_i386_link_hash_table *) bfd_malloc (amt);
   if (ret == NULL)
     return NULL;
 
   if (! _bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc))
     {
-      bfd_release (abfd, ret);
+      free (ret);
       return NULL;
     }
 
@@ -561,6 +564,7 @@ elf_i386_link_hash_table_create (abfd)
   ret->srelplt = NULL;
   ret->sdynbss = NULL;
   ret->srelbss = NULL;
+  ret->sym_sec.abfd = NULL;
 
   return &ret->elf.root;
 }
@@ -833,6 +837,9 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
                      || (h->elf_link_hash_flags
                          & ELF_LINK_HASH_DEF_REGULAR) == 0)))
            {
+             struct elf_i386_dyn_relocs *p;
+             struct elf_i386_dyn_relocs **head;
+
              /* We must copy these reloc types into the output file.
                 Create a reloc section in dynobj and make room for
                 this reloc.  */
@@ -840,11 +847,10 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
                {
                  const char *name;
                  bfd *dynobj;
+                 unsigned int strndx = elf_elfheader (abfd)->e_shstrndx;
+                 unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name;
 
-                 name = (bfd_elf_string_from_elf_section
-                         (abfd,
-                          elf_elfheader (abfd)->e_shstrndx,
-                          elf_section_data (sec)->rel_hdr.sh_name));
+                 name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
                  if (name == NULL)
                    return false;
 
@@ -883,35 +889,42 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
                 relocations we need for this symbol.  */
              if (h != NULL)
                {
-                 struct elf_i386_link_hash_entry *eh;
-                 struct elf_i386_dyn_relocs *p;
-
-                 eh = (struct elf_i386_link_hash_entry *) h;
-                 p = eh->dyn_relocs;
-
-                 if (p == NULL || p->sec != sec)
-                   {
-                     bfd_size_type amt = sizeof *p;
-                     p = ((struct elf_i386_dyn_relocs *)
-                          bfd_alloc (htab->elf.dynobj, amt));
-                     if (p == NULL)
-                       return false;
-                     p->next = eh->dyn_relocs;
-                     eh->dyn_relocs = p;
-                     p->sec = sec;
-                     p->count = 0;
-                     p->pc_count = 0;
-                   }
-
-                 p->count += 1;
-                 if (ELF32_R_TYPE (rel->r_info) == R_386_PC32)
-                   p->pc_count += 1;
+                 head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs;
                }
              else
                {
-                 /* Track dynamic relocs needed for local syms too.  */
-                 elf_section_data (sec)->local_dynrel += 1;
+                 /* Track dynamic relocs needed for local syms too.
+                    We really need local syms available to do this
+                    easily.  Oh well.  */
+
+                 asection *s;
+                 s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
+                                                sec, r_symndx);
+                 if (s == NULL)
+                   return false;
+
+                 head = ((struct elf_i386_dyn_relocs **)
+                         &elf_section_data (s)->local_dynrel);
+               }
+
+             p = *head;
+             if (p == NULL || p->sec != sec)
+               {
+                 bfd_size_type amt = sizeof *p;
+                 p = ((struct elf_i386_dyn_relocs *)
+                      bfd_alloc (htab->elf.dynobj, amt));
+                 if (p == NULL)
+                   return false;
+                 p->next = *head;
+                 *head = p;
+                 p->sec = sec;
+                 p->count = 0;
+                 p->pc_count = 0;
                }
+
+             p->count += 1;
+             if (ELF32_R_TYPE (rel->r_info) == R_386_PC32)
+               p->pc_count += 1;
            }
          break;
 
@@ -973,13 +986,7 @@ elf_i386_gc_mark_hook (abfd, info, rel, h, sym)
     }
   else
     {
-      if (!(elf_bad_symtab (abfd)
-           && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
-         && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
-               && sym->st_shndx != SHN_COMMON))
-       {
-         return bfd_section_from_elf_index (abfd, sym->st_shndx);
-       }
+      return bfd_section_from_elf_index (abfd, sym->st_shndx);
     }
 
   return NULL;
@@ -1000,13 +1007,8 @@ elf_i386_gc_sweep_hook (abfd, info, sec, relocs)
   const Elf_Internal_Rela *rel, *relend;
   unsigned long r_symndx;
   struct elf_link_hash_entry *h;
-  bfd *dynobj;
-
-  elf_section_data (sec)->local_dynrel = 0;
 
-  dynobj = elf_hash_table (info)->dynobj;
-  if (dynobj == NULL)
-    return true;
+  elf_section_data (sec)->local_dynrel = NULL;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
@@ -1105,7 +1107,9 @@ elf_i386_adjust_dynamic_symbol (info, h)
       if (h->plt.refcount <= 0
          || (! info->shared
              && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
-             && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0))
+             && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0
+             && h->root.type != bfd_link_hash_undefweak
+             && h->root.type != bfd_link_hash_undefined))
        {
          /* This case can occur if we saw a PLT32 reloc in an input
             file, but the symbol was never referred to by a dynamic
@@ -1246,10 +1250,15 @@ allocate_dynrelocs (h, inf)
   struct elf_i386_link_hash_entry *eh;
   struct elf_i386_dyn_relocs *p;
 
-  if (h->root.type == bfd_link_hash_indirect
-      || h->root.type == bfd_link_hash_warning)
+  if (h->root.type == bfd_link_hash_indirect)
     return true;
 
+  if (h->root.type == bfd_link_hash_warning)
+    /* When warning symbols are created, they **replace** the "real"
+       entry in the hash table, thus we never get to see the real
+       symbol in a hash traversal.  So look at it now.  */
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
   info = (struct bfd_link_info *) inf;
   htab = elf_i386_hash_table (info);
 
@@ -1393,7 +1402,7 @@ allocate_dynrelocs (h, inf)
 
       eh->dyn_relocs = NULL;
 
-    keep:
+    keep: ;
     }
 
   /* Finally, allocate space.  */
@@ -1416,6 +1425,9 @@ readonly_dynrelocs (h, inf)
   struct elf_i386_link_hash_entry *eh;
   struct elf_i386_dyn_relocs *p;
 
+  if (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 (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
@@ -1480,12 +1492,28 @@ elf_i386_size_dynamic_sections (output_bfd, info)
 
       for (s = ibfd->sections; s != NULL; s = s->next)
        {
-         bfd_size_type count = elf_section_data (s)->local_dynrel;
+         struct elf_i386_dyn_relocs *p;
 
-         if (count != 0)
+         for (p = *((struct elf_i386_dyn_relocs **)
+                    &elf_section_data (s)->local_dynrel);
+              p != NULL;
+              p = p->next)
            {
-             srel = elf_section_data (s)->sreloc;
-             srel->_raw_size += count * sizeof (Elf32_External_Rel);
+             if (!bfd_is_abs_section (p->sec)
+                 && bfd_is_abs_section (p->sec->output_section))
+               {
+                 /* Input section has been discarded, either because
+                    it is a copy of a linkonce section or due to
+                    linker script /DISCARD/, so we'll be discarding
+                    the relocs too.  */
+               }
+             else if (p->count != 0)
+               {
+                 srel = elf_section_data (p->sec)->sreloc;
+                 srel->_raw_size += p->count * sizeof (Elf32_External_Rel);
+                 if ((p->sec->output_section->flags & SEC_READONLY) != 0)
+                   info->flags |= DF_TEXTREL;
+               }
            }
        }
 
@@ -1606,7 +1634,9 @@ elf_i386_size_dynamic_sections (output_bfd, info)
 
          /* If any dynamic relocs apply to a read-only section,
             then we need a DT_TEXTREL entry.  */
-         elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, (PTR) info);
+         if ((info->flags & DF_TEXTREL) == 0)
+           elf_link_hash_traverse (&htab->elf, readonly_dynrelocs,
+                                   (PTR) info);
 
          if ((info->flags & DF_TEXTREL) != 0)
            {
@@ -1747,6 +1777,30 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
          relocation = (sec->output_section->vma
                        + sec->output_offset
                        + sym->st_value);
+         if ((sec->flags & SEC_MERGE)
+             && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+           {
+             asection *msec;
+             bfd_vma addend;
+
+             if (howto->src_mask != 0xffffffff)
+               {
+                 (*_bfd_error_handler)
+                   (_("%s(%s+0x%lx): %s relocation against SEC_MERGE section"),
+                    bfd_archive_filename (input_bfd),
+                    bfd_get_section_name (input_bfd, input_section),
+                    (long) rel->r_offset, howto->name);
+                 return false;
+               }
+
+             addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             msec = sec;
+             addend =
+               _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
+               - relocation;
+             addend += msec->output_section->vma + msec->output_offset;
+             bfd_put_32 (input_bfd, addend, contents + rel->r_offset);
+           }
        }
       else
        {
@@ -1924,8 +1978,14 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
 
        case R_386_32:
        case R_386_PC32:
+         /* 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)
+           break;
+
          if ((info->shared
-              && (input_section->flags & SEC_ALLOC) != 0
               && (r_type != R_386_PC32
                   || (h != NULL
                       && h->dynindx != -1
@@ -1933,7 +1993,6 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
                           || (h->elf_link_hash_flags
                               & ELF_LINK_HASH_DEF_REGULAR) == 0))))
              || (!info->shared
-                 && (input_section->flags & SEC_ALLOC) != 0
                  && h != NULL
                  && h->dynindx != -1
                  && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
@@ -1954,28 +2013,20 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
                 time.  */
 
              skip = false;
-
-             if (elf_section_data (input_section)->stab_info == NULL)
-               outrel.r_offset = rel->r_offset;
-             else
-               {
-                 off = (_bfd_stab_section_offset
-                        (output_bfd, htab->elf.stab_info, input_section,
-                         &elf_section_data (input_section)->stab_info,
-                         rel->r_offset));
-                 if (off == (bfd_vma) -1)
-                   skip = true;
-                 outrel.r_offset = off;
-               }
-
+             relocate = false;
+
+             outrel.r_offset =
+               _bfd_elf_section_offset (output_bfd, info, input_section,
+                                        rel->r_offset);
+             if (outrel.r_offset == (bfd_vma) -1)
+               skip = true;
+             else if (outrel.r_offset == (bfd_vma) -2)
+               skip = true, relocate = true;
              outrel.r_offset += (input_section->output_section->vma
                                  + input_section->output_offset);
 
              if (skip)
-               {
-                 memset (&outrel, 0, sizeof outrel);
-                 relocate = false;
-               }
+               memset (&outrel, 0, sizeof outrel);
              else if (h != NULL
                       && h->dynindx != -1
                       && (r_type == R_386_PC32
@@ -1983,11 +2034,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
                           || !info->symbolic
                           || (h->elf_link_hash_flags
                               & ELF_LINK_HASH_DEF_REGULAR) == 0))
-
-               {
-                 relocate = false;
-                 outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
-               }
+               outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
              else
                {
                  /* This symbol is local, or marked to become local.  */
@@ -2010,7 +2057,6 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
              if (! relocate)
                continue;
            }
-
          break;
 
        default:
This page took 0.029328 seconds and 4 git commands to generate.