Check symbols with undefine version.
authorH.J. Lu <hjl.tools@gmail.com>
Thu, 8 Aug 2002 03:50:18 +0000 (03:50 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Thu, 8 Aug 2002 03:50:18 +0000 (03:50 +0000)
14 files changed:
bfd/ChangeLog
bfd/elflink.h
include/ChangeLog
include/bfdlink.h
ld/ChangeLog
ld/ld.texinfo
ld/ldlang.c
ld/ldmain.c
ld/lexsup.c
ld/testsuite/ChangeLog
ld/testsuite/ld-elfvers/vers.exp
ld/testsuite/ld-elfvers/vers1.map
ld/testsuite/ld-elfvers/vers18.map
ld/testsuite/ld-elfvers/vers8.map

index 41dc63ea619ada2bad40c412ebdd0e38cc1db2c7..40a824e683e1e9145b4856686328764c2c8f6292 100644 (file)
@@ -1,3 +1,11 @@
+2002-08-07  H.J. Lu <hjl@gnu.org>
+
+       * elflink.h (NAME(bfd_elf,size_dynamic_sections)): Check symbol
+       with undefined version if needed.
+       (elf_link_assign_sym_version): Match a default symbol with a
+       version without definition. No need to hide the default
+       definition separately.
+
 2002-08-08  Alan Modra  <amodra@bigpond.net.au>
 
        * elflink.h (elf_link_output_extsym): Don't output symbols from
index 59cc397a209c4edc073892d74e23b76c6e11bb17..b1732e43c2f0c6345d30a165bd9cdd91ee71d067 100644 (file)
@@ -2938,6 +2938,9 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       struct elf_info_failed eif;
       struct elf_link_hash_entry *h;
       asection *dynstr;
+      struct bfd_elf_version_tree *t;
+      struct bfd_elf_version_expr *d;
+      boolean all_defined;
 
       *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
       BFD_ASSERT (*sinterpptr != NULL || info->shared);
@@ -3018,6 +3021,54 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            return false;
        }
 
+      /* Make all global versions with definiton.  */
+      for (t = verdefs; t != NULL; t = t->next)
+       for (d = t->globals; d != NULL; d = d->next)
+         if (!d->symver && strchr (d->pattern, '*') == NULL)
+           {
+             const char *verstr, *name;
+             size_t namelen, verlen, newlen;
+             char *newname, *p;
+             struct elf_link_hash_entry *newh;
+
+             name = d->pattern;
+             namelen = strlen (name);
+             verstr = t->name;
+             verlen = strlen (verstr);
+             newlen = namelen + verlen + 3; 
+
+             newname = (char *) bfd_malloc ((bfd_size_type) newlen);
+             if (newname == NULL)
+               return false;
+             memcpy (newname, name, namelen);
+
+             /* Check the hidden versioned definition.  */
+             p = newname + namelen;
+             *p++ = ELF_VER_CHR;
+             memcpy (p, verstr, verlen + 1);
+             newh = elf_link_hash_lookup (elf_hash_table (info),
+                                          newname, false, false,
+                                          false);
+             if (newh == NULL
+                 || (newh->root.type != bfd_link_hash_defined
+                     && newh->root.type != bfd_link_hash_defweak))
+               {
+                 /* Check the default versioned definition.  */
+                 *p++ = ELF_VER_CHR;
+                 memcpy (p, verstr, verlen + 1);
+                 newh = elf_link_hash_lookup (elf_hash_table (info),
+                                              newname, false, false,
+                                              false);
+               }
+             free (newname);
+
+             /* Mark this version if there is a definition.  */
+             if (newh != NULL
+                 && (newh->root.type == bfd_link_hash_defined
+                     || newh->root.type == bfd_link_hash_defweak))
+               d->symver = 1;
+           }
+
       /* Attach all the symbols to their version information.  */
       asvinfo.output_bfd = output_bfd;
       asvinfo.info = info;
@@ -3030,6 +3081,28 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       if (asvinfo.failed)
        return false;
 
+      if (!info->allow_undefined_version)
+       {
+         /* Check if all global versions have a definiton.  */
+         all_defined = true;
+         for (t = verdefs; t != NULL; t = t->next)
+           for (d = t->globals; d != NULL; d = d->next)
+             if (!d->symver && !d->script
+                 && strchr (d->pattern, '*') == NULL)
+               {
+                 (*_bfd_error_handler)
+                   (_("%s: undefined version: %s"),
+                    d->pattern, t->name);
+                 all_defined = false;
+               }
+
+         if (!all_defined)
+           {
+             bfd_set_error (bfd_error_bad_value);
+             return false;
+           }
+       }
+
       /* Find all symbols which were defined in a dynamic object and make
         the backend pick a reasonable value for them.  */
       elf_link_hash_traverse (elf_hash_table (info),
@@ -4258,7 +4331,6 @@ elf_link_assign_sym_version (h, data)
            (_("%s: undefined versioned symbol name %s"),
             bfd_get_filename (sinfo->output_bfd), h->root.root.string);
          bfd_set_error (bfd_error_bad_value);
-       error_return:
          sinfo->failed = true;
          return false;
        }
@@ -4283,18 +4355,34 @@ elf_link_assign_sym_version (h, data)
        {
          if (t->globals != NULL)
            {
+             boolean matched;
+
+             matched = false;
              for (d = t->globals; d != NULL; d = d->next)
                {
                  if ((*d->match) (d, h->root.root.string))
                    {
-                     h->verinfo.vertree = t;
-                     local_ver = NULL;
-                     break;
+                     if (d->symver)
+                       matched = true;
+                     else
+                       {
+                         /* There is a version without definition.  Make
+                            the symbol the default definition for this
+                            version.  */
+                         h->verinfo.vertree = t;
+                         local_ver = NULL;
+                         d->script = 1;
+                         break;
+                       }
                    }
                }
 
              if (d != NULL)
                break;
+             else if (matched)
+               /* There is no undefined version for this symbol. Hide the
+                  default one.  */
+               (*bed->elf_backend_hide_symbol) (info, h, true);
            }
 
          if (t->locals != NULL)
@@ -4327,43 +4415,6 @@ elf_link_assign_sym_version (h, data)
              (*bed->elf_backend_hide_symbol) (info, h, true);
            }
        }
-
-      /* We need to check if a hidden versioned definition should
-        hide the default one.  */
-      if (h->dynindx != -1 && h->verinfo.vertree != NULL)
-       {
-         const char *verstr, *name;
-         size_t namelen, verlen, newlen;
-         char *newname;
-         struct elf_link_hash_entry *newh;
-
-         name = h->root.root.string;
-         namelen = strlen (name);
-         verstr = h->verinfo.vertree->name;
-         verlen = strlen (verstr);
-         newlen = namelen + verlen + 2;
-
-         newname = (char *) bfd_malloc ((bfd_size_type) newlen);
-         if (newname == NULL)
-           goto error_return;
-         memcpy (newname, name, namelen);
-
-         /* Check the hidden versioned definition.  */
-         p = newname + namelen;
-         *p++ = ELF_VER_CHR;
-         memcpy (p, verstr, verlen + 1);
-         newh = elf_link_hash_lookup (elf_hash_table (info), newname,
-                                      false, false, false);
-
-         if (newh
-             && (newh->root.type == bfd_link_hash_defined
-                 || newh->root.type == bfd_link_hash_defweak))
-           /* We found a hidden versioned definition.  Hide the
-              default one.  */
-           (*bed->elf_backend_hide_symbol) (info, h, true);
-
-         free (newname);
-       }
     }
 
   return true;
index ea51a95c307538118ee86b2aecca17c01a756384..39f18740bd0e87d9431cced49f1c366ca437806f 100644 (file)
@@ -1,3 +1,8 @@
+2002-08-07  H.J. Lu <hjl@gnu.org>
+
+       * bfdlink.h (bfd_link_info): Add allow_undefined_version.
+       (bfd_elf_version_expr): Add symver and script.
+
 2002-07-31  Ian Dall  <ian@sibyl.beware.dropbear.id.au>
 
        * bfdlink.h (bfd_link_common_skip_ar_symbols): New enum.
index c36564f6948a930abf6ae55769c04671c1b4b403..4998fe3dbf7d0dcc835fb6d633a73bef1b7bcc78 100644 (file)
@@ -262,6 +262,9 @@ struct bfd_link_info
   /* true if ok to have multiple definition.  */
   boolean allow_multiple_definition;
 
+  /* true if ok to have version with no definition.  */
+  boolean allow_undefined_version;
+
   /* Which symbols to strip.  */
   enum bfd_link_strip strip;
 
@@ -602,6 +605,10 @@ struct bfd_elf_version_expr
   const char *pattern;
   /* Matching function.  */
   int (*match) PARAMS((struct bfd_elf_version_expr *, const char *));
+  /* Defined by ".symver".  */
+  unsigned int symver: 1;
+  /* Defined by version script.  */
+  unsigned int script : 1;
 };
 
 /* Version dependencies.  */
index a587652de5b5de7c3bc88013eac6734f9d84e6c9..1afde2ac3ceb83d2b982605d11e880636f62bde9 100644 (file)
@@ -1,3 +1,17 @@
+2002-08-07  H.J. Lu <hjl@gnu.org>
+
+       * ld.texinfo: Document --no-undefined-version.
+
+       * ldlang.c (lang_new_vers_pattern): Set the `symver' and
+       `script.' fields to 0.
+
+       * ldmain.c (main): Initialize the allow_undefined_version to
+       true.
+
+       * lexsup.c (OPTION_NO_UNDEFINED_VERSION): New.
+       (ld_options): Add --no-undefined-version.
+       (parse_args): Support OPTION_NO_UNDEFINED_VERSION.
+
 2002-08-07  Nick Clifton  <nickc@redhat.com>
 
        * emultempl/armelf.em (arm_elf_before_allocation): Only search for
index dadc75b726d9793e5a47000bd55b9a566640039c..12030c06f177811f8c6ea8232e142d660dc92c65 100644 (file)
@@ -1102,6 +1102,12 @@ select which function is most appropriate for the current architecture.
 I.E. dynamically select an appropriate memset function.  Apparently it
 is also normal for HPPA shared libraries to have undefined symbols.
 
+@kindex --no-undefined-version
+@item --no-undefined-version
+Normally when a symbol has an undefined version, the linker will ignore
+it. This option disallows symbols with undefined version and a fatal error
+will be issued instead.
+
 @kindex --no-warn-mismatch
 @item --no-warn-mismatch
 Normally @command{ld} will give an error if you try to link together input
index c26082910026e2eb115aa71efcf3a63a6646a6e9..a777e5a435845b0dd9c2c63e281fba5831bbcc26 100644 (file)
@@ -5132,6 +5132,8 @@ lang_new_vers_pattern (orig, new, lang)
   ret = (struct bfd_elf_version_expr *) xmalloc (sizeof *ret);
   ret->next = orig;
   ret->pattern = new;
+  ret->symver = 0;
+  ret->script = 0;
 
   if (lang == NULL || strcasecmp (lang, "C") == 0)
     ret->match = lang_vers_match_lang_c;
index b50ef431599eb93a825676daa407a4c8d28ab1ec..84baa4ddf0aff3aa43bc4cae472e569e48864a45 100644 (file)
@@ -240,6 +240,7 @@ main (argc, argv)
   link_info.no_undefined = false;
   link_info.allow_shlib_undefined = false;
   link_info.allow_multiple_definition = false;
+  link_info.allow_undefined_version = true;
   link_info.strip = strip_none;
   link_info.discard = discard_sec_merge;
   link_info.keep_memory = true;
index ddaf692935f39d58d0e50fee426bfcc992a32063..4acb4fd6a94b5ada83bc30fc01cd905eab55481f 100644 (file)
@@ -127,7 +127,8 @@ int parsing_defsym = 0;
 #define OPTION_TARGET_HELP              (OPTION_UNIQUE + 1)
 #define OPTION_ALLOW_SHLIB_UNDEFINED   (OPTION_TARGET_HELP + 1)
 #define OPTION_ALLOW_MULTIPLE_DEFINITION (OPTION_ALLOW_SHLIB_UNDEFINED + 1)
-#define OPTION_DISCARD_NONE            (OPTION_ALLOW_MULTIPLE_DEFINITION + 1)
+#define OPTION_NO_UNDEFINED_VERSION    (OPTION_ALLOW_MULTIPLE_DEFINITION + 1)
+#define OPTION_DISCARD_NONE            (OPTION_NO_UNDEFINED_VERSION + 1)
 #define OPTION_SPARE_DYNAMIC_TAGS      (OPTION_DISCARD_NONE + 1)
 #define OPTION_NO_DEFINE_COMMON                (OPTION_SPARE_DYNAMIC_TAGS + 1)
 #define OPTION_NOSTDLIB                        (OPTION_NO_DEFINE_COMMON + 1)
@@ -322,6 +323,8 @@ static const struct ld_option ld_options[] =
      '\0', NULL, N_("Allow undefined symbols in shared objects"), TWO_DASHES },
   { {"allow-multiple-definition", no_argument, NULL, OPTION_ALLOW_MULTIPLE_DEFINITION},
      '\0', NULL, N_("Allow multiple definitions"), TWO_DASHES },
+  { {"no-undefined-version", no_argument, NULL, OPTION_NO_UNDEFINED_VERSION},
+     '\0', NULL, N_("Disallow undefined version"), TWO_DASHES },
   { {"no-warn-mismatch", no_argument, NULL, OPTION_NO_WARN_MISMATCH},
       '\0', NULL, N_("Don't warn about mismatched input files"), TWO_DASHES},
   { {"no-whole-archive", no_argument, NULL, OPTION_NO_WHOLE_ARCHIVE},
@@ -767,6 +770,9 @@ parse_args (argc, argv)
        case OPTION_ALLOW_MULTIPLE_DEFINITION:
          link_info.allow_multiple_definition = true;
          break;
+       case OPTION_NO_UNDEFINED_VERSION:
+         link_info.allow_undefined_version = false;
+         break;
        case OPTION_NO_WARN_MISMATCH:
          command_line.warn_mismatch = false;
          break;
index b492850d3f0c7e78ffb03e37e6700c104c2930ed..0c2e3b90899e3cb46cec350152c015c0831d89ba 100644 (file)
@@ -1,3 +1,11 @@
+2002-08-07  H.J. Lu <hjl@gnu.org>
+
+       * ld-elfvers/vers.exp: Add --no-undefined-version.
+
+       * ld-elfvers/vers1.map: Remove the unused foo1 and foo2.
+       * ld-elfvers/vers8.map: Likewise.
+       * ld-elfvers/vers18.map: Likewise.
+
 2002-07-30  John David Anglin  <dave@hiauly1.hia.nrc.ca>
 
        * ld-discard/discard.exp, ld-scripts/phdrs.exp, ld-scripts/phdrs2.exp,
index 1acc0e6559f723b5726cbb77fe820437c8472fa0..738072926ce762a80c1f7c0c8684c2e14d5cf41c 100644 (file)
@@ -62,7 +62,7 @@ set tmpdir tmpdir
 set VOBJDUMP_FLAGS --private-headers
 set DOBJDUMP_FLAGS --dynamic-syms
 set SOBJDUMP_FLAGS --syms
-set shared --shared
+set shared "--shared --no-undefined-version"
 set script --version-script
 
 proc test_ar { test lib object expect } {
@@ -643,7 +643,7 @@ proc build_exec { test source execname flags solibname verexp versymexp symexp }
     global CC
     global CFLAGS
 
-    set shared --shared
+    set shared "--shared --no-undefined-version"
     set script --version-script
     if ![ld_compile "$CC -S $CFLAGS" $srcdir/$subdir/$source $tmpdir/$execname.s]     {
        unresolved "$test"
index 8fc37bcaf0fd19c38a9b182e701033122a409c75..767915cd7f811ae1b6ce58b23883fef0d08e260f 100644 (file)
@@ -1,6 +1,4 @@
 VERS_1.1 {
-        global:
-                foo1;
         local:
                 hide_old*; 
                 hide_original*; 
@@ -8,7 +6,6 @@ VERS_1.1 {
 };
 
 VERS_1.2 {
-                foo2;
 } VERS_1.1;
 
 VERS_2.0 {
index eac2b0e3dcb94ef938a9b60bdca0aa35b5a37b29..8dcff39b6f03be2c1b9418e96d1bffd67e89a738 100644 (file)
@@ -1,6 +1,4 @@
 VERS_1.1 {
-        global:
-                foo1;
         local:
                 hide_old*; 
                 hide_original*; 
@@ -8,7 +6,6 @@ VERS_1.1 {
 };
 
 VERS_1.2 {
-                foo2;
 } VERS_1.1;
 
 VERS_2.0 {
index 26359559d9f95ba471f923d7343fe5cb62a58e26..c24fb107afee7e3b49650e5a7a2f2a5e1d61a5b7 100644 (file)
@@ -1,7 +1,5 @@
 VERSION {
        VERS_1.1 {
-                global:
-                        foo1;
                 local:
                         hide_old*; 
                         hide_original*; 
@@ -9,7 +7,6 @@ VERSION {
        };
        
        VERS_1.2 {
-                        foo2;
        } VERS_1.1;
        
        VERS_2.0 {