2001-11-30 H.J. Lu <hjl@gnu.org>
authorH.J. Lu <hjl.tools@gmail.com>
Fri, 30 Nov 2001 15:50:56 +0000 (15:50 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Fri, 30 Nov 2001 15:50:56 +0000 (15:50 +0000)
* elflink.h (elf_add_default_symbol): New.
(elf_link_add_object_symbols): Call elf_add_default_symbol ()
to create an indirect symbol from the default for the symbol
with the default version if needed.

bfd/ChangeLog
bfd/elflink.h

index 599f5f0..420fe6f 100644 (file)
@@ -1,3 +1,10 @@
+2001-11-30  H.J. Lu <hjl@gnu.org>
+
+       * elflink.h (elf_add_default_symbol): New.
+       (elf_link_add_object_symbols): Call elf_add_default_symbol ()
+       to create an indirect symbol from the default for the symbol
+       with the default version if needed.
+
 2001-11-29  "Peter.Schauer" <Peter.Schauer@regent.e-technik.tu-muenchen.de>
 
        * elf.c (elfcore_grok_prstatus): Do not overwite the core signal
index c01e03d..d78832d 100644 (file)
@@ -39,9 +39,14 @@ static boolean elf_link_add_object_symbols
 static boolean elf_link_add_archive_symbols
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_merge_symbol
-  PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
-          asection **, bfd_vma *, struct elf_link_hash_entry **,
-          boolean *, boolean *, boolean *, boolean));
+  PARAMS ((bfd *, struct bfd_link_info *, const char *,
+          Elf_Internal_Sym *, asection **, bfd_vma *,
+          struct elf_link_hash_entry **, boolean *, boolean *,
+          boolean *, boolean));
+static boolean elf_add_default_symbol
+  PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
+          const char *, Elf_Internal_Sym *, asection **, bfd_vma *,
+          boolean *, boolean, boolean));
 static boolean elf_export_symbol
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_finalize_dynstr
@@ -894,6 +899,243 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
   return true;
 }
 
+/* This function is called to create an indirect symbol from the
+   default for the symbol with the default version if needed. The
+   symbol is described by H, NAME, SYM, SEC, VALUE, and OVERRIDE.  We
+   set DYNSYM if the new indirect symbol is dynamic. DT_NEEDED
+   indicates if it comes from a DT_NEEDED entry of a shared object.  */
+
+static boolean
+elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
+                       dynsym, override, dt_needed)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+     const char *name;
+     Elf_Internal_Sym *sym;
+     asection **sec;
+     bfd_vma *value;
+     boolean *dynsym;
+     boolean override;
+     boolean dt_needed;
+{
+  boolean type_change_ok;
+  boolean size_change_ok;
+  char *shortname;
+  struct elf_link_hash_entry *hi;
+  struct elf_backend_data *bed;
+  boolean collect;
+  boolean dynamic;
+  char *p;
+
+  /* If this symbol has a version, and it is the default version, we
+     create an indirect symbol from the default name to the fully
+     decorated name.  This will cause external references which do not
+     specify a version to be bound to this version of the symbol.  */
+  p = strchr (name, ELF_VER_CHR);
+  if (p == NULL || p[1] != ELF_VER_CHR)
+    return true;
+
+  if (override)
+    {
+      /* We are overridden by an old defition. We need to check if we
+        need to crreate the indirect symbol from the default name.  */
+      hi = elf_link_hash_lookup (elf_hash_table (info), name, true,
+                                false, false);
+      BFD_ASSERT (hi != NULL);
+      if (hi == h)
+       return true;
+      while (hi->root.type == bfd_link_hash_indirect
+            || hi->root.type == bfd_link_hash_warning)
+       {
+         hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
+         if (hi == h)
+           return true;
+       }
+    }
+
+  bed = get_elf_backend_data (abfd);
+  collect = bed->collect;
+  dynamic = (abfd->flags & DYNAMIC) != 0;
+
+  shortname = bfd_hash_allocate (&info->hash->table,
+                                (size_t) (p - name + 1));
+  if (shortname == NULL)
+    return false;
+  strncpy (shortname, name, (size_t) (p - name));
+  shortname [p - name] = '\0';
+
+  /* We are going to create a new symbol.  Merge it with any existing
+     symbol with this name.  For the purposes of the merge, act as
+     though we were defining the symbol we just defined, although we
+     actually going to define an indirect symbol.  */
+  type_change_ok = false;
+  size_change_ok = false;
+  if (! elf_merge_symbol (abfd, info, shortname, sym, sec, value,
+                         &hi, &override, &type_change_ok,
+                         &size_change_ok, dt_needed))
+    return false;
+
+  if (! override)
+    {
+      if (! (_bfd_generic_link_add_one_symbol
+            (info, abfd, shortname, BSF_INDIRECT, bfd_ind_section_ptr,
+             (bfd_vma) 0, name, false, collect,
+             (struct bfd_link_hash_entry **) &hi)))
+       return false;
+    }
+  else
+    {
+      /* In this case the symbol named SHORTNAME is overriding the
+        indirect symbol we want to add.  We were planning on making
+        SHORTNAME an indirect symbol referring to NAME.  SHORTNAME
+        is the name without a version.  NAME is the fully versioned
+        name, and it is the default version.
+
+        Overriding means that we already saw a definition for the
+        symbol SHORTNAME in a regular object, and it is overriding
+        the symbol defined in the dynamic object.
+
+        When this happens, we actually want to change NAME, the
+        symbol we just added, to refer to SHORTNAME.  This will cause
+        references to NAME in the shared object to become references
+        to SHORTNAME in the regular object.  This is what we expect
+        when we override a function in a shared object: that the
+        references in the shared object will be mapped to the
+        definition in the regular object.  */
+
+      while (hi->root.type == bfd_link_hash_indirect
+            || hi->root.type == bfd_link_hash_warning)
+       hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
+
+      h->root.type = bfd_link_hash_indirect;
+      h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
+      if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
+       {
+         h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC;
+         hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
+         if (hi->elf_link_hash_flags
+             & (ELF_LINK_HASH_REF_REGULAR
+                | ELF_LINK_HASH_DEF_REGULAR))
+           {
+             if (! _bfd_elf_link_record_dynamic_symbol (info, hi))
+               return false;
+           }
+       }
+
+      /* Now set HI to H, so that the following code will set the
+         other fields correctly.  */
+      hi = h;
+    }
+
+  /* If there is a duplicate definition somewhere, then HI may not
+     point to an indirect symbol.  We will have reported an error to
+     the user in that case.  */
+
+  if (hi->root.type == bfd_link_hash_indirect)
+    {
+      struct elf_link_hash_entry *ht;
+
+      /* If the symbol became indirect, then we assume that we have
+        not seen a definition before.  */
+      BFD_ASSERT ((hi->elf_link_hash_flags
+                  & (ELF_LINK_HASH_DEF_DYNAMIC
+                     | ELF_LINK_HASH_DEF_REGULAR)) == 0);
+
+      ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
+      (*bed->elf_backend_copy_indirect_symbol) (ht, hi);
+
+      /* See if the new flags lead us to realize that the symbol must
+        be dynamic.  */
+      if (! *dynsym)
+       {
+         if (! dynamic)
+           {
+             if (info->shared
+                 || ((hi->elf_link_hash_flags
+                      & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+               *dynsym = true;
+           }
+         else
+           {
+             if ((hi->elf_link_hash_flags
+                  & ELF_LINK_HASH_REF_REGULAR) != 0)
+               *dynsym = true;
+           }
+       }
+    }
+
+  /* We also need to define an indirection from the nondefault version
+     of the symbol.  */
+
+  shortname = bfd_hash_allocate (&info->hash->table, strlen (name));
+  if (shortname == NULL)
+    return false;
+  strncpy (shortname, name, (size_t) (p - name));
+  strcpy (shortname + (p - name), p + 1);
+
+  /* Once again, merge with any existing symbol.  */
+  type_change_ok = false;
+  size_change_ok = false;
+  if (! elf_merge_symbol (abfd, info, shortname, sym, sec, value,
+                         &hi, &override, &type_change_ok,
+                         &size_change_ok, dt_needed))
+    return false;
+
+  if (override)
+    {
+      /* Here SHORTNAME is a versioned name, so we don't expect to see
+        the type of override we do in the case above.  */
+      (*_bfd_error_handler)
+       (_("%s: warning: unexpected redefinition of `%s'"),
+        bfd_archive_filename (abfd), shortname);
+    }
+  else
+    {
+      if (! (_bfd_generic_link_add_one_symbol
+            (info, abfd, shortname, BSF_INDIRECT,
+             bfd_ind_section_ptr, (bfd_vma) 0, name, false,
+             collect, (struct bfd_link_hash_entry **) &hi)))
+       return false;
+
+      /* If there is a duplicate definition somewhere, then HI may not
+        point to an indirect symbol.  We will have reported an error
+        to the user in that case.  */
+
+      if (hi->root.type == bfd_link_hash_indirect)
+       {
+         /* If the symbol became indirect, then we assume that we have
+            not seen a definition before.  */
+         BFD_ASSERT ((hi->elf_link_hash_flags
+                      & (ELF_LINK_HASH_DEF_DYNAMIC
+                         | ELF_LINK_HASH_DEF_REGULAR)) == 0);
+
+          (*bed->elf_backend_copy_indirect_symbol) (h, hi);
+
+         /* See if the new flags lead us to realize that the symbol
+            must be dynamic.  */
+         if (! *dynsym)
+           {
+             if (! dynamic)
+               {
+                 if (info->shared
+                     || ((hi->elf_link_hash_flags
+                          & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+                   *dynsym = true;
+               }
+             else
+               {
+                 if ((hi->elf_link_hash_flags
+                      & ELF_LINK_HASH_REF_REGULAR) != 0)
+                   *dynsym = true;
+               }
+           }
+       }
+    }
+
+  return true;
+}
+
 /* Add symbols from an ELF object file to the linker hash table.  */
 
 static boolean
@@ -1373,6 +1615,9 @@ elf_link_add_object_symbols (abfd, info)
       boolean size_change_ok, type_change_ok;
       boolean new_weakdef;
       unsigned int old_alignment;
+      boolean override;
+
+      override = false;
 
       elf_swap_symbol_in (abfd, esym, &sym);
 
@@ -1463,7 +1708,6 @@ elf_link_add_object_symbols (abfd, info)
        {
          Elf_Internal_Versym iver;
          unsigned int vernum = 0;
-         boolean override;
 
          if (ever != NULL)
            {
@@ -1735,217 +1979,13 @@ elf_link_add_object_symbols (abfd, info)
 
          h->elf_link_hash_flags |= new_flag;
 
-         /* If this symbol has a version, and it is the default
-             version, we create an indirect symbol from the default
-             name to the fully decorated name.  This will cause
-             external references which do not specify a version to be
-             bound to this version of the symbol.  */
+         /* Check to see if we need to add an indirect symbol for
+            the default name.  */
          if (definition || h->root.type == bfd_link_hash_common)
-           {
-             char *p;
-
-             p = strchr (name, ELF_VER_CHR);
-             if (p != NULL && p[1] == ELF_VER_CHR)
-               {
-                 char *shortname;
-                 struct elf_link_hash_entry *hi;
-                 boolean override;
-
-                 shortname = bfd_hash_allocate (&info->hash->table,
-                                                (size_t) (p - name + 1));
-                 if (shortname == NULL)
-                   goto error_return;
-                 strncpy (shortname, name, (size_t) (p - name));
-                 shortname[p - name] = '\0';
-
-                 /* We are going to create a new symbol.  Merge it
-                     with any existing symbol with this name.  For the
-                     purposes of the merge, act as though we were
-                     defining the symbol we just defined, although we
-                     actually going to define an indirect symbol.  */
-                 type_change_ok = false;
-                 size_change_ok = false;
-                 if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
-                                         &value, &hi, &override,
-                                         &type_change_ok,
-                                         &size_change_ok, dt_needed))
-                   goto error_return;
-
-                 if (! override)
-                   {
-                     if (! (_bfd_generic_link_add_one_symbol
-                            (info, abfd, shortname, BSF_INDIRECT,
-                             bfd_ind_section_ptr, (bfd_vma) 0, name, false,
-                             collect, (struct bfd_link_hash_entry **) &hi)))
-                       goto error_return;
-                   }
-                 else
-                   {
-                     /* In this case the symbol named SHORTNAME is
-                         overriding the indirect symbol we want to
-                         add.  We were planning on making SHORTNAME an
-                         indirect symbol referring to NAME.  SHORTNAME
-                         is the name without a version.  NAME is the
-                         fully versioned name, and it is the default
-                         version.
-
-                        Overriding means that we already saw a
-                        definition for the symbol SHORTNAME in a
-                        regular object, and it is overriding the
-                        symbol defined in the dynamic object.
-
-                        When this happens, we actually want to change
-                        NAME, the symbol we just added, to refer to
-                        SHORTNAME.  This will cause references to
-                        NAME in the shared object to become
-                        references to SHORTNAME in the regular
-                        object.  This is what we expect when we
-                        override a function in a shared object: that
-                        the references in the shared object will be
-                        mapped to the definition in the regular
-                        object.  */
-
-                     while (hi->root.type == bfd_link_hash_indirect
-                            || hi->root.type == bfd_link_hash_warning)
-                       hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
-
-                     h->root.type = bfd_link_hash_indirect;
-                     h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
-                     if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
-                       {
-                         h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC;
-                         hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
-                         if (hi->elf_link_hash_flags
-                             & (ELF_LINK_HASH_REF_REGULAR
-                                | ELF_LINK_HASH_DEF_REGULAR))
-                           {
-                             if (! _bfd_elf_link_record_dynamic_symbol (info,
-                                                                        hi))
-                               goto error_return;
-                           }
-                       }
-
-                     /* Now set HI to H, so that the following code
-                         will set the other fields correctly.  */
-                     hi = h;
-                   }
-
-                 /* If there is a duplicate definition somewhere,
-                    then HI may not point to an indirect symbol.  We
-                    will have reported an error to the user in that
-                    case.  */
-
-                 if (hi->root.type == bfd_link_hash_indirect)
-                   {
-                     struct elf_link_hash_entry *ht;
-
-                     /* If the symbol became indirect, then we assume
-                        that we have not seen a definition before.  */
-                     BFD_ASSERT ((hi->elf_link_hash_flags
-                                  & (ELF_LINK_HASH_DEF_DYNAMIC
-                                     | ELF_LINK_HASH_DEF_REGULAR))
-                                 == 0);
-
-                     ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
-                     (*bed->elf_backend_copy_indirect_symbol) (ht, hi);
-
-                     /* See if the new flags lead us to realize that
-                        the symbol must be dynamic.  */
-                     if (! dynsym)
-                       {
-                         if (! dynamic)
-                           {
-                             if (info->shared
-                                 || ((hi->elf_link_hash_flags
-                                      & ELF_LINK_HASH_REF_DYNAMIC)
-                                     != 0))
-                               dynsym = true;
-                           }
-                         else
-                           {
-                             if ((hi->elf_link_hash_flags
-                                  & ELF_LINK_HASH_REF_REGULAR) != 0)
-                               dynsym = true;
-                           }
-                       }
-                   }
-
-                 /* We also need to define an indirection from the
-                     nondefault version of the symbol.  */
-
-                 shortname = bfd_hash_allocate (&info->hash->table,
-                                                strlen (name));
-                 if (shortname == NULL)
-                   goto error_return;
-                 strncpy (shortname, name, (size_t) (p - name));
-                 strcpy (shortname + (p - name), p + 1);
-
-                 /* Once again, merge with any existing symbol.  */
-                 type_change_ok = false;
-                 size_change_ok = false;
-                 if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
-                                         &value, &hi, &override,
-                                         &type_change_ok,
-                                         &size_change_ok, dt_needed))
-                   goto error_return;
-
-                 if (override)
-                   {
-                     /* Here SHORTNAME is a versioned name, so we
-                         don't expect to see the type of override we
-                         do in the case above.  */
-                     (*_bfd_error_handler)
-                       (_("%s: warning: unexpected redefinition of `%s'"),
-                        bfd_archive_filename (abfd), shortname);
-                   }
-                 else
-                   {
-                     if (! (_bfd_generic_link_add_one_symbol
-                            (info, abfd, shortname, BSF_INDIRECT,
-                             bfd_ind_section_ptr, (bfd_vma) 0, name, false,
-                             collect, (struct bfd_link_hash_entry **) &hi)))
-                       goto error_return;
-
-                     /* If there is a duplicate definition somewhere,
-                         then HI may not point to an indirect symbol.
-                         We will have reported an error to the user in
-                         that case.  */
-
-                     if (hi->root.type == bfd_link_hash_indirect)
-                       {
-                         /* If the symbol became indirect, then we
-                             assume that we have not seen a definition
-                             before.  */
-                         BFD_ASSERT ((hi->elf_link_hash_flags
-                                      & (ELF_LINK_HASH_DEF_DYNAMIC
-                                         | ELF_LINK_HASH_DEF_REGULAR))
-                                     == 0);
-
-                         (*bed->elf_backend_copy_indirect_symbol) (h, hi);
-
-                         /* See if the new flags lead us to realize
-                             that the symbol must be dynamic.  */
-                         if (! dynsym)
-                           {
-                             if (! dynamic)
-                               {
-                                 if (info->shared
-                                     || ((hi->elf_link_hash_flags
-                                          & ELF_LINK_HASH_REF_DYNAMIC)
-                                         != 0))
-                                   dynsym = true;
-                               }
-                             else
-                               {
-                                 if ((hi->elf_link_hash_flags
-                                      & ELF_LINK_HASH_REF_REGULAR) != 0)
-                                   dynsym = true;
-                               }
-                           }
-                       }
-                   }
-               }
-           }
+           if (! elf_add_default_symbol (abfd, info, h, name, &sym,
+                                         &sec, &value, &dynsym,
+                                         override, dt_needed))
+             goto error_return;
 
          if (dynsym && h->dynindx == -1)
            {