* elflink.h (elf_link_add_object_symbols): Don't decrease the
authorIan Lance Taylor <ian@airs.com>
Fri, 16 May 1997 16:13:33 +0000 (16:13 +0000)
committerIan Lance Taylor <ian@airs.com>
Fri, 16 May 1997 16:13:33 +0000 (16:13 +0000)
  alignment of a common symbol.  If two symbols that look like
  common symbols are found in two shared libraries, and the size is
  different, use the larger size, and warn if --warn-common.  If a
common symbol overrides a definition in a shared library, set the
size to the larger size, and warn if --warn-common.

bfd/ChangeLog
bfd/elflink.h

index 84f3d403a55d862b7661370d38f131ef6e6fcd55..4451ef0283e6e1ad1a308a811212a92e42a20f85 100644 (file)
@@ -1,3 +1,12 @@
+Fri May 16 12:10:52 1997  Ian Lance Taylor  <ian@cygnus.com>
+
+       * elflink.h (elf_link_add_object_symbols): Don't decrease the
+       alignment of a common symbol.  If two symbols that look like
+       common symbols are found in two shared libraries, and the size is
+       different, use the larger size, and warn if --warn-common.  If a
+       common symbol overrides a definition in a shared library, set the
+       size to the larger size, and warn if --warn-common.
+
 Thu May 15 14:31:28 1997  Nick Clifton  <nickc@cygnus.com>
 
        * cpu-arm.c (compatible):  Allow default machine to be polymorphed
index 78f57ffc63e0e85972d5b71b931e1bce2cee202c..a6d06b1633d264d41f03064ebe67671d320fc952 100644 (file)
@@ -695,6 +695,7 @@ elf_link_add_object_symbols (abfd, info)
       boolean definition;
       boolean size_change_ok, type_change_ok;
       boolean new_weakdef;
+      unsigned int old_alignment;
 
       elf_swap_symbol_in (abfd, esym, &sym);
 
@@ -782,6 +783,7 @@ elf_link_add_object_symbols (abfd, info)
 
       size_change_ok = false;
       type_change_ok = get_elf_backend_data (abfd)->type_change_ok;
+      old_alignment = 0;
       if (info->hash->creator->flavour == bfd_target_elf_flavour)
        {
          Elf_Internal_Versym iver;
@@ -860,6 +862,9 @@ elf_link_add_object_symbols (abfd, info)
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
+         /* FIXME: There are too many cases here, and it's too
+             confusing.  This code needs to be reorganized somehow.  */
+
          /* It's OK to change the type if it used to be a weak
              definition, or if the current definition is weak (and
              hence might be ignored).  */
@@ -875,6 +880,9 @@ elf_link_add_object_symbols (abfd, info)
              || h->root.type == bfd_link_hash_undefined)
            size_change_ok = true;
 
+         if (h->root.type == bfd_link_hash_common)
+           old_alignment = h->root.u.c.p->alignment_power;
+
          override = false;
 
          /* If we are looking at a dynamic object, and this is a
@@ -896,6 +904,39 @@ elf_link_add_object_symbols (abfd, info)
                      && (bind == STB_WEAK
                          || ELF_ST_TYPE (sym.st_info) == STT_FUNC)))
                {
+                 /* In the special case of two symbols which look
+                     like common symbols in a dynamic object, set the
+                     size of the symbol to the larger of the two.  */
+                 if ((sec->flags & SEC_ALLOC) != 0
+                     && (sec->flags & SEC_LOAD) == 0
+                     && sym.st_size > 0
+                     && bind != STB_WEAK
+                     && ELF_ST_TYPE (sym.st_info) != STT_FUNC
+                     && h->root.type == bfd_link_hash_defined
+                     && (h->elf_link_hash_flags
+                         & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+                     && (h->root.u.def.section->owner->flags & DYNAMIC) != 0
+                     && (h->root.u.def.section->flags & SEC_ALLOC) != 0
+                     && (h->root.u.def.section->flags & SEC_LOAD) == 0
+                     && h->size > 0
+                     && h->type != STT_FUNC
+                     && sym.st_size != h->size)
+                   {
+                     /* Note that we only warn if the size is
+                         different.  If the size is the same, then we
+                         simply let the first shared library override
+                         the second.  */
+                     if (! ((*info->callbacks->multiple_common)
+                            (info, h->root.root.string,
+                             h->root.u.def.section->owner,
+                             bfd_link_hash_common,
+                             h->size, abfd, bfd_link_hash_common,
+                             sym.st_size)))
+                       goto error_return;
+                     if (sym.st_size > h->size)
+                       h->size = sym.st_size;
+                   }
+
                  override = true;
                  sec = bfd_und_section_ptr;
                  definition = false;
@@ -925,12 +966,12 @@ elf_link_add_object_symbols (abfd, info)
              size_change_ok = true;
            }
 
-         /* Similarly, if we are not looking at a dynamic object, and
-            we have a definition, we want to override any definition
-            we may have from a dynamic object.  Symbols from regular
-            files always take precedence over symbols from dynamic
-            objects, even if they are defined after the dynamic
-            object in the link.  */
+         /* If we are not looking at a dynamic object, and we have a
+            definition, we want to override any definition we may
+            have from a dynamic object.  Symbols from regular files
+            always take precedence over symbols from dynamic objects,
+            even if they are defined after the dynamic object in the
+            link.  */
          if (! dynamic
              && (definition
                  || (bfd_is_com_section (sec)
@@ -958,6 +999,49 @@ elf_link_add_object_symbols (abfd, info)
              h->verinfo.vertree = NULL;
            }
 
+         /* If we are not looking at a shared library and we have a
+             common symbol, and the symbol in the shared library is in
+             an uninitialized section, then treat the shared library
+             symbol as a common symbol.  This will not always be
+             correct, but it should do little harm.  Note that the
+             above condition already handled cases in which a common
+             symbol should simply override the definition in the
+             shared library.  */
+         if (! dynamic
+             && ! override
+             && bfd_is_com_section (sec)
+             && h->root.type == bfd_link_hash_defined
+             && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+             && (h->root.u.def.section->owner->flags & DYNAMIC) != 0
+             && (h->root.u.def.section->flags & SEC_ALLOC) != 0
+             && (h->root.u.def.section->flags & SEC_LOAD) == 0
+             && h->size > 0
+             && h->type != STT_FUNC)
+           {
+             /* It would be best if we could set the hash table entry
+                 to a common symbol, but we don't know what to use for
+                 the section or the alignment.  */
+             if (! ((*info->callbacks->multiple_common)
+                    (info, h->root.root.string,
+                     h->root.u.def.section->owner, bfd_link_hash_common,
+                     h->size, abfd, bfd_link_hash_common, value)))
+               goto error_return;
+
+             if (h->size > value)
+               value = h->size;
+
+             /* FIXME: We no longer know the alignment required by
+                the symbol in the shared library, so we just wind up
+                using the one from the regular object.  */
+
+             override = true;
+             h->root.type = bfd_link_hash_undefined;
+             h->root.u.undef.abfd = h->root.u.def.section->owner;
+             size_change_ok = true;
+             type_change_ok = true;
+             h->verinfo.vertree = NULL;
+           }
+
          if (ever != NULL
              && ! override
              && vernum > 1
@@ -1001,10 +1085,16 @@ elf_link_add_object_symbols (abfd, info)
          new_weakdef = true;
        }
 
-      /* Get the alignment of a common symbol.  */
+      /* Set the alignment of a common symbol.  */
       if (sym.st_shndx == SHN_COMMON
          && h->root.type == bfd_link_hash_common)
-       h->root.u.c.p->alignment_power = bfd_log2 (sym.st_value);
+       {
+         unsigned int align;
+
+         align = bfd_log2 (sym.st_value);
+         if (align > old_alignment)
+           h->root.u.c.p->alignment_power = align;
+       }
 
       if (info->hash->creator->flavour == bfd_target_elf_flavour)
        {