bfd/
authorH.J. Lu <hjl.tools@gmail.com>
Mon, 28 Apr 2003 03:31:36 +0000 (03:31 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Mon, 28 Apr 2003 03:31:36 +0000 (03:31 +0000)
2003-04-27  H.J. Lu <hjl@gnu.org>

* elf-bfd.h (ELF_LINK_DYNAMIC_DEF): New.
(ELF_LINK_DYNAMIC_WEAK): New.

* elflink.h (elf_merge_symbol): Add one argument to indicate if
a symbol should be skipped. Ignore definitions in dynamic
objects for symbols with non-default visibility.
(elf_add_default_symbol): Adjusted.
(elf_link_add_object_symbols): Check if a symbol should be
skipped. Don't merge the visibility field with the one from
a dynamic object.
(elf_link_check_versioned_symbol): Use undef_bfd.
(elf_link_output_extsym): Warn if a forced local symbol is
referenced from dynamic objects. Make non-weak undefined symbol
with non-default visibility a fatal error.

ld/testsuite/

2003-04-27  H.J. Lu <hjl@gnu.org>

* ld-elfvsb/elfvsb.dat: Updated.
* ld-elfvsb/elfvsb.exp: Likewise.
* ld-elfvsb/main.c: Likewise.
* ld-elfvsb/sh1.c: Likewise.
* ld-elfvsb/sh2.c: Likewise.

bfd/ChangeLog
bfd/elf-bfd.h
bfd/elflink.h
ld/testsuite/ChangeLog
ld/testsuite/ld-elfvsb/elfvsb.dat
ld/testsuite/ld-elfvsb/elfvsb.exp
ld/testsuite/ld-elfvsb/main.c
ld/testsuite/ld-elfvsb/sh1.c
ld/testsuite/ld-elfvsb/sh2.c

index 3833e05f681bb405afb406d905b391a9e04dbcb9..2bd268c9c1b99492c82ed137685811c0d566b9e4 100644 (file)
@@ -1,3 +1,20 @@
+2003-04-27  H.J. Lu <hjl@gnu.org>
+
+       * elf-bfd.h (ELF_LINK_DYNAMIC_DEF): New.
+       (ELF_LINK_DYNAMIC_WEAK): New.
+
+       * elflink.h (elf_merge_symbol): Add one argument to indicate if
+       a symbol should be skipped. Ignore definitions in dynamic
+       objects for symbols with non-default visibility.
+       (elf_add_default_symbol): Adjusted.
+       (elf_link_add_object_symbols): Check if a symbol should be
+       skipped. Don't merge the visibility field with the one from
+       a dynamic object.
+       (elf_link_check_versioned_symbol): Use undef_bfd.
+       (elf_link_output_extsym): Warn if a forced local symbol is
+       referenced from dynamic objects. Make non-weak undefined symbol
+       with non-default visibility a fatal error.
+
 2003-04-27  Daniel Jacobowitz  <drow@mvista.com>
 
        * configure.in: Bump version on HEAD to 2.14.90.
index 2e5587cf798990f56284954ae697bcad27d79383..f15353ce2d6cec7f2c0df43c7e397cfc9fc9b7bf 100644 (file)
@@ -204,6 +204,10 @@ struct elf_link_hash_entry
   /* Symbol is referenced by a non-GOT/non-PLT relocation.  This is
      not currently set by all the backends.  */
 #define ELF_LINK_NON_GOT_REF 010000
+  /* Symbol has a definition in a shared object.  */
+#define ELF_LINK_DYNAMIC_DEF 020000
+  /* Symbol is weak in all shared objects.  */
+#define ELF_LINK_DYNAMIC_WEAK 040000
 };
 
 /* Records local symbols to be emitted in the dynamic symbol table.  */
index 505bfb12154e8be9c75a37abb63b9e0384e7e001..5889e1c70f2eee3c4d3caefce2ddd64ac9c4cf19 100644 (file)
@@ -42,7 +42,7 @@ static bfd_boolean elf_merge_symbol
   PARAMS ((bfd *, struct bfd_link_info *, const char *,
           Elf_Internal_Sym *, asection **, bfd_vma *,
           struct elf_link_hash_entry **, bfd_boolean *, bfd_boolean *,
-          bfd_boolean *, bfd_boolean));
+          bfd_boolean *, bfd_boolean *, bfd_boolean));
 static bfd_boolean elf_add_default_symbol
   PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
           const char *, Elf_Internal_Sym *, asection **, bfd_vma *,
@@ -463,7 +463,7 @@ elf_link_add_archive_symbols (abfd, info)
    a shared object.  */
 
 static bfd_boolean
-elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
+elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash, skip,
                  override, type_change_ok, size_change_ok, dt_needed)
      bfd *abfd;
      struct bfd_link_info *info;
@@ -472,6 +472,7 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
      asection **psec;
      bfd_vma *pvalue;
      struct elf_link_hash_entry **sym_hash;
+     bfd_boolean *skip;
      bfd_boolean *override;
      bfd_boolean *type_change_ok;
      bfd_boolean *size_change_ok;
@@ -484,6 +485,7 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
   bfd *oldbfd;
   bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
 
+  *skip = FALSE;
   *override = FALSE;
 
   sec = *psec;
@@ -606,6 +608,57 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
   else
     olddef = TRUE;
 
+  /* We need to rememeber if a symbol has a definition in a dynamic
+     object or is weak in all dynamic objects. Internal and hidden
+     visibility will make it unavailable to dynamic objects.  */
+  if (newdyn && (h->elf_link_hash_flags & ELF_LINK_DYNAMIC_DEF) == 0)
+    {
+      if (!bfd_is_und_section (sec))
+       h->elf_link_hash_flags |= ELF_LINK_DYNAMIC_DEF;
+      else
+       {
+         /* Check if this symbol is weak in all dynamic objects. If it
+            is the first time we see it in a dynamic object, we mark
+            if it is weak. Otherwise, we clear it.  */
+         if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0)
+           { 
+             if (bind == STB_WEAK)
+               h->elf_link_hash_flags |= ELF_LINK_DYNAMIC_WEAK;
+           }
+         else if (bind != STB_WEAK)
+           h->elf_link_hash_flags &= ~ELF_LINK_DYNAMIC_WEAK;
+       }
+    }
+
+  /* If the old symbol has non-default visibility, we ignore the new
+     definition from a dynamic object.  */
+  if (newdyn
+      && ELF_ST_VISIBILITY (h->other)
+      && !bfd_is_und_section (sec))
+    {
+      *skip = TRUE;
+      /* Make sure this symbol is dynamic.  */
+      h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
+      /* FIXME: Should we check type and size for protected symbol?  */
+      return _bfd_elf_link_record_dynamic_symbol (info, h);
+    }
+  else if (!newdyn
+          && ELF_ST_VISIBILITY (sym->st_other)
+          && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+    {
+      /* If the new symbol with non-default visibility comes from a
+        relocatable file and the old definition comes from a dynamic
+        object, we remove the old definition.  */
+      h->root.type = bfd_link_hash_new;
+      h->root.u.undef.abfd = NULL;
+      h->elf_link_hash_flags &= ~ELF_LINK_HASH_DEF_DYNAMIC;
+      h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
+      /* FIXME: Should we check type and size for protected symbol?  */
+      h->size = 0;
+      h->type = 0;
+      return TRUE;
+    }
+
   /* NEWDYNCOMMON and OLDDYNCOMMON indicate whether the new or old
      symbol, respectively, appears to be a common symbol in a dynamic
      object.  If a symbol appears in an uninitialized section, and is
@@ -934,6 +987,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, psec, value,
 {
   bfd_boolean type_change_ok;
   bfd_boolean size_change_ok;
+  bfd_boolean skip;
   char *shortname;
   struct elf_link_hash_entry *hi;
   struct bfd_link_hash_entry *bh;
@@ -989,7 +1043,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, psec, value,
   size_change_ok = FALSE;
   sec = *psec;
   if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
-                         &hi, &override, &type_change_ok,
+                         &hi, &skip, &override, &type_change_ok,
                          &size_change_ok, dt_needed))
     return FALSE;
 
@@ -1098,7 +1152,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, psec, value,
   size_change_ok = FALSE;
   sec = *psec;
   if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
-                         &hi, &override, &type_change_ok,
+                         &hi, &skip, &override, &type_change_ok,
                          &size_change_ok, dt_needed))
     return FALSE;
 
@@ -1740,6 +1794,7 @@ elf_link_add_object_symbols (abfd, info)
        {
          Elf_Internal_Versym iver;
          unsigned int vernum = 0;
+         bfd_boolean skip;
 
          if (ever != NULL)
            {
@@ -1837,10 +1892,14 @@ elf_link_add_object_symbols (abfd, info)
            }
 
          if (! elf_merge_symbol (abfd, info, name, isym, &sec, &value,
-                                 sym_hash, &override, &type_change_ok,
-                                 &size_change_ok, dt_needed))
+                                 sym_hash, &skip, &override,
+                                 &type_change_ok, &size_change_ok,
+                                 dt_needed))
            goto error_free_vers;
 
+         if (skip)
+           continue;
+
          if (override)
            definition = FALSE;
 
@@ -2020,9 +2079,10 @@ elf_link_add_object_symbols (abfd, info)
              h->type = ELF_ST_TYPE (isym->st_info);
            }
 
-         /* If st_other has a processor-specific meaning, specific code
-            might be needed here.  */
-         if (isym->st_other != 0)
+         /* If st_other has a processor-specific meaning, specific
+            code might be needed here. We never merge the visibility
+            attribute with the one from a dynamic object.  */
+         if (isym->st_other != 0 && !dynamic)
            {
              unsigned char hvis, symvis, other, nvis;
 
@@ -2089,7 +2149,7 @@ elf_link_add_object_symbols (abfd, info)
                                          override, dt_needed))
              goto error_free_vers;
 
-         if (definition && (abfd->flags & DYNAMIC) == 0)
+         if (definition && !dynamic)
            {
              char *p = strchr (name, ELF_VER_CHR);
              if (p != NULL && p[1] != ELF_VER_CHR)
@@ -6106,7 +6166,7 @@ elf_link_check_versioned_symbol (info, h)
 
   if ((undef_bfd->flags & DYNAMIC) == 0
       || info->hash->creator->flavour != bfd_target_elf_flavour
-      || elf_dt_soname (h->root.u.undef.abfd) == NULL)
+      || elf_dt_soname (undef_bfd) == NULL)
     return FALSE;
 
   for (loaded = elf_hash_table (info)->loaded;
@@ -6273,6 +6333,28 @@ elf_link_output_extsym (h, data)
        }
     }
 
+  /* We should also warn if a forced local symbol is referenced from
+     shared libraries.  */
+  if (! finfo->info->relocateable
+      && (! finfo->info->shared || ! finfo->info->allow_shlib_undefined)
+      && (h->elf_link_hash_flags
+         & (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC
+            | ELF_LINK_DYNAMIC_DEF | ELF_LINK_DYNAMIC_WEAK))
+        == (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC))
+    {
+      (*_bfd_error_handler)
+       (_("%s: %s symbol `%s' in %s is referenced by DSO"),
+        bfd_get_filename (finfo->output_bfd),
+        ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+        ? "internal"
+        : ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
+          ? "hidden" : "local",
+        h->root.root.string,
+        bfd_archive_filename (h->root.u.def.section->owner));
+      eoinfo->failed = TRUE;
+      return FALSE;
+    }
+
   /* We don't want to output symbols that have never been mentioned by
      a regular file, or that we have been told to strip.  However, if
      h->indx is set to -2, the symbol is used by a reloc and we must
@@ -6433,10 +6515,25 @@ elf_link_output_extsym (h, data)
       sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
     }
 
-  /* If a symbol is not defined locally, we clear the visibility field.  */
+  /* If a non-weak symbol with non-default visibility is not defined
+     locally, it is a fatal error.  */
   if (! finfo->info->relocateable
+      && ELF_ST_VISIBILITY (sym.st_other)
+      && ELF_ST_BIND (sym.st_info) != STB_WEAK
+      && h->root.type != bfd_link_hash_undefweak
       && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
-    sym.st_other &= ~ ELF_ST_VISIBILITY (-1);
+    {
+      (*_bfd_error_handler)
+       (_("%s: %s symbol `%s' isn't defined"),
+         bfd_get_filename (finfo->output_bfd),
+         ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED
+         ? "protected"
+         : ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL
+           ? "internal" : "hidden",
+         h->root.root.string);
+      eoinfo->failed = TRUE;
+      return FALSE;
+    }
 
   /* If this symbol should be put in the .dynsym section, then put it
      there now.  We already know the symbol index.  We also fill in
index a0ae7fdf8bd950c5801a1529bbea44819b7f552a..8334e587d853655e611b87ca2a649f3b9c8c09f1 100644 (file)
@@ -1,3 +1,11 @@
+2003-04-27  H.J. Lu <hjl@gnu.org>
+
+       * ld-elfvsb/elfvsb.dat: Updated.
+       * ld-elfvsb/elfvsb.exp: Likewise.
+       * ld-elfvsb/main.c: Likewise.
+       * ld-elfvsb/sh1.c: Likewise.
+       * ld-elfvsb/sh2.c: Likewise.
+
 2003-04-26  Stephane Carrez  <stcarrez@nerim.fr>
 
        * ld-m68hc11/bug-3331.d: New test.
index e94a178e14bf343f9a60fb23cf517fb73d89f3b7..bad3b1ec1422f0f221a8e3b7b641cf0e8c3f7a66 100644 (file)
@@ -20,3 +20,7 @@ main_visibility_check () == 1
 visibility_checkvar () == 1
 visibility_checkvarptr () == 1
 main_visibility_checkvar () == 1
+main_visibility_checkcom () == 1
+shlib_visibility_checkcom () == 1
+main_visibility_checkweak () == 1
+shlib_visibility_checkweak () == 1
index c4f82f45c07f3fad6cc0c1e86e7c3a3c9899d30d..220e28251a59208116c3f1f7ec7aa5e3ea3a5531 100644 (file)
@@ -144,6 +144,8 @@ proc visibility_test { visibility progname testname main sh1 sh2 dat args } {
            pass "$testname"
        } else { if { [ string match $visibility "hidden_undef_def" ]
             && [regexp ".*/main.c.*: undefined reference to \`visibility\'" $link_output]
+            && [regexp ".*/main.c.*: undefined reference to \`visibility_def\'" $link_output]
+            && [regexp ".*/main.c.*: undefined reference to \`visibility_func\'" $link_output]
             && [regexp ".*/main.c.*: undefined reference to \`visibility_var\'" $link_output] } {
            pass "$testname"
        } else {
index 26542b8a1fcf3aeb5d12afcac1a37dbfd5cbbe02..6ce97bf4b25045ab970f8ac22908b3cc7f097294 100644 (file)
@@ -42,6 +42,18 @@ extern int visibility_checkvar ();
 extern int visibility_checkvarptr ();
 extern int visibility_varval ();
 extern void *visibility_varptr ();
+extern int shlib_visibility_checkcom ();
+extern int shlib_visibility_checkweak ();
+
+int shlib_visibility_com = 1;
+
+int shlib_visibility_var_weak = 1;
+
+int
+shlib_visibility_func_weak ()
+{
+  return 1;
+}
 
 #ifdef HIDDEN_WEAK_TEST
 #define WEAK_TEST
@@ -81,6 +93,23 @@ main_visibility_checkvar ()
   return visibility_varval () != visibility_var
         && visibility_varptr () != &visibility_var;
 }
+
+#ifndef PROTECTED_UNDEF_TEST
+int shared_data = 1;
+asm (".protected shared_data");
+
+int
+shared_func ()
+{
+  return 1;
+}
+
+asm (".protected shared_func");
+
+extern int * shared_data_p ();
+typedef int (*func) ();
+extern func shared_func_p ();
+#endif
 #else
 static int
 main_visibility_check ()
@@ -121,10 +150,57 @@ shlib_overriddencall2 ()
   return 8;
 }
 
+#ifdef HIDDEN_NORMAL_TEST
+int visibility_com;
+asm (".hidden visibility_com");
+
+int
+main_visibility_checkcom ()
+{
+  return visibility_com == 0;
+}
+
+int
+main_visibility_checkweak ()
+{
+  return 1;
+}
+#elif defined (HIDDEN_UNDEF_TEST)
+extern int visibility_def;
+asm (".hidden visibility_def");
+extern int visibility_func ();
+asm (".hidden visibility_func");
+
+int
+main_visibility_checkcom ()
+{
+  return &visibility_def != NULL;
+}
+
+int
+main_visibility_checkweak ()
+{
+  return &visibility_func != NULL;
+}
+#else
+int
+main_visibility_checkcom ()
+{
+  return 1;
+}
+
+int
+main_visibility_checkweak ()
+{
+  return 1;
+}
+#endif
+
 int
 main ()
 {
   int (*p) ();
+  int ret = 0;
 
   printf ("mainvar == %d\n", mainvar);
   printf ("overriddenvar == %d\n", overriddenvar);
@@ -173,6 +249,27 @@ main ()
          visibility_checkvarptr ());
   printf ("main_visibility_checkvar () == %d\n",
          main_visibility_checkvar ());
-  return 0;
+  printf ("main_visibility_checkcom () == %d\n",
+         main_visibility_checkcom ());
+  printf ("shlib_visibility_checkcom () == %d\n",
+         shlib_visibility_checkcom ());
+  printf ("main_visibility_checkweak () == %d\n",
+         main_visibility_checkweak ());
+  printf ("shlib_visibility_checkweak () == %d\n",
+         shlib_visibility_checkweak ());
+
+#if !defined (PROTECTED_UNDEF_TEST) && defined (PROTECTED_TEST)
+  if (&shared_data != shared_data_p ())
+    ret = 1;
+  p = shared_func_p ();
+  if (shared_func != p)
+    ret = 1;
+  if (shared_data != *shared_data_p ())
+    ret = 1;
+  if (shared_func () != (*p) () )
+    ret = 1;
+#endif
+
+  return ret;
 }
 #endif
index 41bc4934d22cfc1c9b4caba745f3b85866f2cb87..2b9b9eeb52308e27ea872bdd6fc6db0582959bb5 100644 (file)
@@ -323,3 +323,54 @@ asm (".protected visibility");
 asm (".protected visibility_var");
 #endif
 #endif
+
+#ifdef HIDDEN_NORMAL_TEST
+int shlib_visibility_com;
+asm (".hidden shlib_visibility_com");
+
+int
+shlib_visibility_checkcom ()
+{
+  return shlib_visibility_com == 0;
+}
+
+int
+shlib_visibility_checkweak ()
+{
+  return 1;
+}
+#else
+int
+shlib_visibility_checkcom ()
+{
+  return 1;
+}
+
+int
+shlib_visibility_checkweak ()
+{
+  return 1;
+}
+#endif
+
+#ifdef PROTECTED_TEST
+int shared_data = 100;
+int *
+shared_data_p ()
+{
+  return &shared_data;
+}
+int
+shared_func ()
+{
+  return 100;
+}
+void *
+shared_func_p ()
+{
+  return shared_func;
+}
+#endif
index 6ed30bc52e1f5817565266ff9d0260526356d4bc..ef6b2f16f61a7a245c3374eb6b0ac6783b48dcb2 100644 (file)
@@ -5,6 +5,10 @@
    the shared library.  */
 int shlibvar2 = 4;
 
+/* This variable is defined here, and shouldn't be used to resolve a
+   reference with non-default visibility in another shared library.  */
+int visibility_com = 2;
+
 /* This function is called by another file in the shared library.  */
 
 int
@@ -21,4 +25,22 @@ visibility ()
 }
 
 int visibility_var = 2;
+
+int visibility_def = 2;
+
+int
+visibility_func ()
+{
+  return 2;
+}
+#endif
+
+#ifdef HIDDEN_WEAK_TEST
+int visibility_var_weak = 2;
+
+int
+visibility_func_weak ()
+{
+  return 2;
+}
 #endif