2004-12-05 Tomer Levi <Tomer.Levi@nsc.com>
[deliverable/binutils-gdb.git] / bfd / elf.c
index a82387ca63834b16fb39a95d47109870b9dd7804..c14b91a53c1c43ad14e731ced99eb28ed4e38d3d 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1192,7 +1192,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
   if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL)
       || (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL))
     {
-      if (! _bfd_elf_slurp_version_tables (abfd))
+      if (! _bfd_elf_slurp_version_tables (abfd, FALSE))
        return FALSE;
     }
 
@@ -2725,18 +2725,35 @@ assign_section_numbers (bfd *abfd)
   unsigned int section_number, secn;
   Elf_Internal_Shdr **i_shdrp;
   bfd_size_type amt;
+  struct bfd_elf_section_data *d;
 
   section_number = 1;
 
   _bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd));
 
+  /* Put SHT_GROUP sections first.  */
   for (sec = abfd->sections; sec; sec = sec->next)
     {
-      struct bfd_elf_section_data *d = elf_section_data (sec);
+      d = elf_section_data (sec);
 
-      if (section_number == SHN_LORESERVE)
-       section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-      d->this_idx = section_number++;
+      if (d->this_hdr.sh_type == SHT_GROUP)
+       {
+         if (section_number == SHN_LORESERVE)
+           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+         d->this_idx = section_number++;
+       }
+    }
+
+  for (sec = abfd->sections; sec; sec = sec->next)
+    {
+      d = elf_section_data (sec);
+
+      if (d->this_hdr.sh_type != SHT_GROUP)
+       {
+         if (section_number == SHN_LORESERVE)
+           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+         d->this_idx = section_number++;
+       }
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name);
       if ((sec->flags & SEC_RELOC) == 0)
        d->rel_idx = 0;
@@ -6027,10 +6044,94 @@ _bfd_elf_canonicalize_dynamic_reloc (bfd *abfd,
 /* Read in the version information.  */
 
 bfd_boolean
-_bfd_elf_slurp_version_tables (bfd *abfd)
+_bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver)
 {
   bfd_byte *contents = NULL;
   bfd_size_type amt;
+  unsigned int freeidx = 0;
+
+  if (elf_dynverref (abfd) != 0)
+    {
+      Elf_Internal_Shdr *hdr;
+      Elf_External_Verneed *everneed;
+      Elf_Internal_Verneed *iverneed;
+      unsigned int i;
+
+      hdr = &elf_tdata (abfd)->dynverref_hdr;
+
+      amt = (bfd_size_type) hdr->sh_info * sizeof (Elf_Internal_Verneed);
+      elf_tdata (abfd)->verref = bfd_zalloc (abfd, amt);
+      if (elf_tdata (abfd)->verref == NULL)
+       goto error_return;
+
+      elf_tdata (abfd)->cverrefs = hdr->sh_info;
+
+      contents = bfd_malloc (hdr->sh_size);
+      if (contents == NULL)
+       goto error_return;
+      if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
+         || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
+       goto error_return;
+
+      everneed = (Elf_External_Verneed *) contents;
+      iverneed = elf_tdata (abfd)->verref;
+      for (i = 0; i < hdr->sh_info; i++, iverneed++)
+       {
+         Elf_External_Vernaux *evernaux;
+         Elf_Internal_Vernaux *ivernaux;
+         unsigned int j;
+
+         _bfd_elf_swap_verneed_in (abfd, everneed, iverneed);
+
+         iverneed->vn_bfd = abfd;
+
+         iverneed->vn_filename =
+           bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+                                            iverneed->vn_file);
+         if (iverneed->vn_filename == NULL)
+           goto error_return;
+
+         amt = iverneed->vn_cnt;
+         amt *= sizeof (Elf_Internal_Vernaux);
+         iverneed->vn_auxptr = bfd_alloc (abfd, amt);
+
+         evernaux = ((Elf_External_Vernaux *)
+                     ((bfd_byte *) everneed + iverneed->vn_aux));
+         ivernaux = iverneed->vn_auxptr;
+         for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++)
+           {
+             _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux);
+
+             ivernaux->vna_nodename =
+               bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+                                                ivernaux->vna_name);
+             if (ivernaux->vna_nodename == NULL)
+               goto error_return;
+
+             if (j + 1 < iverneed->vn_cnt)
+               ivernaux->vna_nextptr = ivernaux + 1;
+             else
+               ivernaux->vna_nextptr = NULL;
+
+             evernaux = ((Elf_External_Vernaux *)
+                         ((bfd_byte *) evernaux + ivernaux->vna_next));
+
+             if (ivernaux->vna_other > freeidx)
+               freeidx = ivernaux->vna_other;
+           }
+
+         if (i + 1 < hdr->sh_info)
+           iverneed->vn_nextref = iverneed + 1;
+         else
+           iverneed->vn_nextref = NULL;
+
+         everneed = ((Elf_External_Verneed *)
+                     ((bfd_byte *) everneed + iverneed->vn_next));
+       }
+
+      free (contents);
+      contents = NULL;
+    }
 
   if (elf_dynverdef (abfd) != 0)
     {
@@ -6067,6 +6168,13 @@ _bfd_elf_slurp_version_tables (bfd *abfd)
                     ((bfd_byte *) everdef + iverdefmem.vd_next));
        }
 
+      if (default_imported_symver)
+       {
+         if (freeidx > maxidx)
+           maxidx = ++freeidx;
+         else
+           freeidx = ++maxidx;
+       }
       amt = (bfd_size_type) maxidx * sizeof (Elf_Internal_Verdef);
       elf_tdata (abfd)->verdef = bfd_zalloc (abfd, amt);
       if (elf_tdata (abfd)->verdef == NULL)
@@ -6130,85 +6238,46 @@ _bfd_elf_slurp_version_tables (bfd *abfd)
       free (contents);
       contents = NULL;
     }
-
-  if (elf_dynverref (abfd) != 0)
+  else if (default_imported_symver)
     {
-      Elf_Internal_Shdr *hdr;
-      Elf_External_Verneed *everneed;
-      Elf_Internal_Verneed *iverneed;
-      unsigned int i;
-
-      hdr = &elf_tdata (abfd)->dynverref_hdr;
-
-      amt = (bfd_size_type) hdr->sh_info * sizeof (Elf_Internal_Verneed);
-      elf_tdata (abfd)->verref = bfd_zalloc (abfd, amt);
-      if (elf_tdata (abfd)->verref == NULL)
-       goto error_return;
-
-      elf_tdata (abfd)->cverrefs = hdr->sh_info;
+      if (freeidx < 3)
+       freeidx = 3;
+      else
+       freeidx++;
 
-      contents = bfd_malloc (hdr->sh_size);
-      if (contents == NULL)
-       goto error_return;
-      if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
-         || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
+      amt = (bfd_size_type) freeidx * sizeof (Elf_Internal_Verdef);
+      elf_tdata (abfd)->verdef = bfd_zalloc (abfd, amt);
+      if (elf_tdata (abfd)->verdef == NULL)
        goto error_return;
 
-      everneed = (Elf_External_Verneed *) contents;
-      iverneed = elf_tdata (abfd)->verref;
-      for (i = 0; i < hdr->sh_info; i++, iverneed++)
-       {
-         Elf_External_Vernaux *evernaux;
-         Elf_Internal_Vernaux *ivernaux;
-         unsigned int j;
-
-         _bfd_elf_swap_verneed_in (abfd, everneed, iverneed);
-
-         iverneed->vn_bfd = abfd;
-
-         iverneed->vn_filename =
-           bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
-                                            iverneed->vn_file);
-         if (iverneed->vn_filename == NULL)
-           goto error_return;
-
-         amt = iverneed->vn_cnt;
-         amt *= sizeof (Elf_Internal_Vernaux);
-         iverneed->vn_auxptr = bfd_alloc (abfd, amt);
-
-         evernaux = ((Elf_External_Vernaux *)
-                     ((bfd_byte *) everneed + iverneed->vn_aux));
-         ivernaux = iverneed->vn_auxptr;
-         for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++)
-           {
-             _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux);
+      elf_tdata (abfd)->cverdefs = freeidx;
+    }
 
-             ivernaux->vna_nodename =
-               bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
-                                                ivernaux->vna_name);
-             if (ivernaux->vna_nodename == NULL)
-               goto error_return;
+  /* Create a default version based on the soname.  */
+  if (default_imported_symver)
+    {
+      Elf_Internal_Verdef *iverdef;
+      Elf_Internal_Verdaux *iverdaux;
 
-             if (j + 1 < iverneed->vn_cnt)
-               ivernaux->vna_nextptr = ivernaux + 1;
-             else
-               ivernaux->vna_nextptr = NULL;
+      iverdef = &elf_tdata (abfd)->verdef[freeidx - 1];;
 
-             evernaux = ((Elf_External_Vernaux *)
-                         ((bfd_byte *) evernaux + ivernaux->vna_next));
-           }
+      iverdef->vd_version = VER_DEF_CURRENT;
+      iverdef->vd_flags = 0;
+      iverdef->vd_ndx = freeidx;
+      iverdef->vd_cnt = 1;
 
-         if (i + 1 < hdr->sh_info)
-           iverneed->vn_nextref = iverneed + 1;
-         else
-           iverneed->vn_nextref = NULL;
+      iverdef->vd_bfd = abfd;
 
-         everneed = ((Elf_External_Verneed *)
-                     ((bfd_byte *) everneed + iverneed->vn_next));
-       }
+      iverdef->vd_nodename = bfd_elf_get_dt_soname (abfd);
+      if (iverdef->vd_nodename == NULL)
+       goto error_return;
+      iverdef->vd_nextdef = NULL;
+      amt = (bfd_size_type) sizeof (Elf_Internal_Verdaux);
+      iverdef->vd_auxptr = bfd_alloc (abfd, amt);
 
-      free (contents);
-      contents = NULL;
+      iverdaux = iverdef->vd_auxptr;
+      iverdaux->vda_nodename = iverdef->vd_nodename;
+      iverdaux->vda_nextptr = NULL;
     }
 
   return TRUE;
@@ -6307,13 +6376,24 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED,
                   const char **functionname_ptr)
 {
   const char *filename;
-  asymbol *func;
+  asymbol *func, *file;
   bfd_vma low_func;
   asymbol **p;
+  /* ??? Given multiple file symbols, it is impossible to reliably
+     choose the right file name for global symbols.  File symbols are
+     local symbols, and thus all file symbols must sort before any
+     global symbols.  The ELF spec may be interpreted to say that a
+     file symbol must sort before other local symbols, but currently
+     ld -r doesn't do this.  So, for ld -r output, it is possible to
+     make a better choice of file name for local symbols by ignoring
+     file symbols appearing after a given local symbol.  */
+  enum { nothing_seen, symbol_seen, file_after_symbol_seen } state;
 
   filename = NULL;
   func = NULL;
+  file = NULL;
   low_func = 0;
+  state = nothing_seen;
 
   for (p = symbols; *p != NULL; p++)
     {
@@ -6326,8 +6406,12 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED,
        default:
          break;
        case STT_FILE:
-         filename = bfd_asymbol_name (&q->symbol);
-         break;
+         file = &q->symbol;
+         if (state == symbol_seen)
+           state = file_after_symbol_seen;
+         continue;
+       case STT_SECTION:
+         continue;
        case STT_NOTYPE:
        case STT_FUNC:
          if (bfd_get_section (&q->symbol) == section
@@ -6336,9 +6420,18 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED,
            {
              func = (asymbol *) q;
              low_func = q->symbol.value;
+             if (file == NULL)
+               filename = NULL;
+             else if (ELF_ST_BIND (q->internal_elf_sym.st_info) != STB_LOCAL
+                      && state == file_after_symbol_seen)
+               filename = NULL;
+             else
+               filename = bfd_asymbol_name (file);
            }
          break;
        }
+      if (state == nothing_seen)
+       state = symbol_seen;
     }
 
   if (func == NULL)
This page took 0.027835 seconds and 4 git commands to generate.