* elflink.h (elf_merge_symbol): In the case of a new defined
authorIan Lance Taylor <ian@airs.com>
Tue, 24 Jun 1997 02:28:03 +0000 (02:28 +0000)
committerIan Lance Taylor <ian@airs.com>
Tue, 24 Jun 1997 02:28:03 +0000 (02:28 +0000)
symbol overriding an old defined symbol, return the hash table
entry which we modify, even if it is the target of an
indirection.
(elf_link_add_object_symbols): If the real name of the symbol gets
overridden, convert the versioned symbol into an indirect symbol
to the real symbol.

bfd/ChangeLog
bfd/elflink.h

index 4ba11fca60da6e51a0a7c2fd168fc3d921e232d1..1abf0b1bff3deced7f216710f40bd834f95d71c1 100644 (file)
@@ -1,5 +1,13 @@
 Mon Jun 23 18:03:27 1997  Ian Lance Taylor  <ian@cygnus.com>
 
+       * elflink.h (elf_merge_symbol): In the case of a new defined
+       symbol overriding an old defined symbol, return the hash table
+       entry which we modify, even if it is the target of an
+       indirection.
+       (elf_link_add_object_symbols): If the real name of the symbol gets
+       overridden, convert the versioned symbol into an indirect symbol
+       to the real symbol.
+
        * elflink.h (elf_merge_symbol): New static function, broken out of
        elf_link_add_object_symbols.
        (elf_link_add_object_symbols): Call it.
index f72465084cd36edc6fc5163d9fb2290618616178..2cbd80a8485b7397d239bc429dacc6aa8d7b7d7a 100644 (file)
@@ -568,6 +568,13 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
         NULL, so that it is correct for a regular symbol.  */
 
       h->verinfo.vertree = NULL;
+
+      /* In this special case, if H is the target of an indirection,
+         we want the caller to frob with H rather than with the
+         indirect symbol.  That will permit the caller to redefine the
+         target of the indirection, rather than the indirect symbol
+         itself.  */
+      *sym_hash = h;
     }
 
   /* Handle the special case of a new common symbol merging with an
@@ -1376,70 +1383,113 @@ elf_link_add_object_symbols (abfd, info)
                              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.  */
+
+                     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 (! _bfd_elf_link_record_dynamic_symbol (info, 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.  */
+                     /* Now set HI to H, so that the following code
+                         will set the other fields correctly.  */
+                     hi = h;
+                   }
 
-                     if (hi->root.type == bfd_link_hash_indirect)
+                 /* 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;
+
+                     /* Copy down any references that we may have
+                        already seen to the symbol which just became
+                        indirect.  */
+                     ht->elf_link_hash_flags |=
+                       (hi->elf_link_hash_flags
+                        & (ELF_LINK_HASH_REF_DYNAMIC
+                           | ELF_LINK_HASH_REF_REGULAR));
+
+                     /* Copy over the global table offset entry.
+                        This may have been already set up by a
+                        check_relocs routine.  */
+                     if (ht->got_offset == (bfd_vma) -1)
                        {
-                         /* 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->got_offset = hi->got_offset;
+                         hi->got_offset = (bfd_vma) -1;
+                       }
+                     BFD_ASSERT (hi->got_offset == (bfd_vma) -1);
 
-                         /* Copy down any references that we may have
-                             already seen to the symbol which just
-                             became indirect.  */
-                         h->elf_link_hash_flags |=
-                           (hi->elf_link_hash_flags
-                            & (ELF_LINK_HASH_REF_DYNAMIC
-                               | ELF_LINK_HASH_REF_REGULAR));
+                     if (ht->dynindx == -1)
+                       {
+                         ht->dynindx = hi->dynindx;
+                         ht->dynstr_index = hi->dynstr_index;
+                         hi->dynindx = -1;
+                         hi->dynstr_index = 0;
+                       }
+                     BFD_ASSERT (hi->dynindx == -1);
 
-                         /* Copy over the global table offset entry.
-                             This may have been already set up by a
-                             check_relocs routine.  */
-                         if (h->got_offset == (bfd_vma) -1)
-                           {
-                             h->got_offset = hi->got_offset;
-                             hi->got_offset = (bfd_vma) -1;
-                           }
-                         BFD_ASSERT (hi->got_offset == (bfd_vma) -1);
+                     /* FIXME: There may be other information to copy
+                        over for particular targets.  */
 
-                         if (h->dynindx == -1)
+                     /* See if the new flags lead us to realize that
+                        the symbol must be dynamic.  */
+                     if (! dynsym)
+                       {
+                         if (! dynamic)
                            {
-                             h->dynindx = hi->dynindx;
-                             h->dynstr_index = hi->dynstr_index;
-                             hi->dynindx = -1;
-                             hi->dynstr_index = 0;
+                             if (info->shared
+                                 || ((hi->elf_link_hash_flags
+                                      & ELF_LINK_HASH_REF_DYNAMIC)
+                                     != 0))
+                               dynsym = true;
                            }
-                         BFD_ASSERT (hi->dynindx == -1);
-
-                         /* FIXME: There may be other information to
-                             copy over for particular targets.  */
-
-                         /* See if the new flags lead us to realize
-                             that the symbol must be dynamic.  */
-                         if (! dynsym)
+                         else
                            {
-                             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 ((hi->elf_link_hash_flags
+                                  & ELF_LINK_HASH_REF_REGULAR) != 0)
+                               dynsym = true;
                            }
                        }
                    }
@@ -1460,7 +1510,16 @@ elf_link_add_object_symbols (abfd, info)
                                          &type_change_ok, &size_change_ok))
                    goto error_return;
 
-                 if (! override)
+                 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_get_filename (abfd), shortname);
+                   }
+                 else
                    {
                      if (! (_bfd_generic_link_add_one_symbol
                             (info, abfd, shortname, BSF_INDIRECT,