PATCH: Add double-quoted version strings

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

PATCH: Add double-quoted version strings

Mark Mitchell

GNU ld supports the extern "C++" syntax in version files so that you
can specify un-mangled names for C++ identifiers.  However, at present
its difficult to use that facility in all cases.  For example, you
cannot specify a space in such a name, and a "*" will be interpreted
as a wildcard character, not as the literal "*" in a demangled name
like "f(int *)".

This patch permits double-quoted strings to be used in the version
script, with the semantics that double-quoted strings are interpreted
literally, not as glob patterns.

OK?  

--
Mark Mitchell
CodeSourcery, LLC
[hidden email]

2005-10-12  Mark Mitchell  <[hidden email]>

        * ld.texino: Describe double-quoted string syntax for version
        nodes.
        * ldlang.h (lang_new_vers_pattern): Add literal_p parameter.
        * ldgram.y (vers_defns): Allow NAME as well as VERS_IDENTIFIER.
        Adjust calls to lang_new_vers_pattern to pass literal_p argument.
        * ldlang.c (lang_vers_match): Fix indentation.  Do not glob-match
        version nodes without a pattern.
        (lang_new_vers_pattern): Add literal_p parameter.
        (lang_do_version_exports_section): Pass it.

2005-10-12  Mark Mitchell  <[hidden email]>

        * ld-elfvers/vers.exp: Add vers31.
        * ld-elfvers/vers31.c: New file.
        * ld-elfvers/vers31.dsym: Likewise.
        * ld-elfvers/vers31.map: Likewise.
        * ld-elfvers/vers31.ver: Likewise.

Index: ld.texinfo
===================================================================
RCS file: /cvs/src/src/ld/ld.texinfo,v
retrieving revision 1.148
diff -c -5 -p -r1.148 ld.texinfo
*** ld.texinfo 28 Sep 2005 00:34:21 -0000 1.148
--- ld.texinfo 13 Oct 2005 00:59:36 -0000
*************** VERS_1.2 @{
*** 4287,4296 ****
--- 4292,4305 ----
  foo2;
  @} VERS_1.1;
 
  VERS_2.0 @{
  bar1; bar2;
+ extern "C++" @{      
+ ns::*;
+ "int f(int, double)";
+          @}        
  @} VERS_1.2;
  @end smallexample
 
  This example version script defines three version nodes.  The first
  version node defined is @samp{VERS_1.1}; it has no other dependencies.
*************** The script binds the symbol @samp{foo1}
*** 4298,4307 ****
--- 4307,4318 ----
  a number of symbols to local scope so that they are not visible outside
  of the shared library; this is done using wildcard patterns, so that any
  symbol whose name begins with @samp{old}, @samp{original}, or @samp{new}
  is matched.  The wildcard patterns available are the same as those used
  in the shell when matching filenames (also known as ``globbing'').
+ However, if you specify the symbol name inside double quotes, then the
+ name is treated as literal, rather than as a glob pattern.
 
  Next, the version script defines node @samp{VERS_1.2}.  This node
  depends upon @samp{VERS_1.1}.  The script binds the symbol @samp{foo2}
  to the version node @samp{VERS_1.2}.
 
Index: ldgram.y
===================================================================
RCS file: /cvs/src/src/ld/ldgram.y,v
retrieving revision 1.47
diff -c -5 -p -r1.47 ldgram.y
*** ldgram.y 28 Sep 2005 00:34:21 -0000 1.47
--- ldgram.y 13 Oct 2005 00:59:36 -0000
*************** vers_tag:
*** 1217,1231 ****
  ;
 
  vers_defns:
  VERS_IDENTIFIER
  {
!  $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang);
  }
  | vers_defns ';' VERS_IDENTIFIER
  {
!  $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang);
  }
  | vers_defns ';' EXTERN NAME '{'
  {
   $<name>$ = ldgram_vers_current_lang;
   ldgram_vers_current_lang = $4;
--- 1217,1239 ----
  ;
 
  vers_defns:
  VERS_IDENTIFIER
  {
!  $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang, FALSE);
! }
!         |       NAME
! {
!  $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang, TRUE);
  }
  | vers_defns ';' VERS_IDENTIFIER
  {
!  $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang, FALSE);
! }
! | vers_defns ';' NAME
! {
!  $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang, TRUE);
  }
  | vers_defns ';' EXTERN NAME '{'
  {
   $<name>$ = ldgram_vers_current_lang;
   ldgram_vers_current_lang = $4;
*************** vers_defns:
*** 1248,1278 ****
   $$ = $5;
   ldgram_vers_current_lang = $<name>4;
  }
  | GLOBAL
  {
!  $$ = lang_new_vers_pattern (NULL, "global", ldgram_vers_current_lang);
  }
  | vers_defns ';' GLOBAL
  {
!  $$ = lang_new_vers_pattern ($1, "global", ldgram_vers_current_lang);
  }
  | LOCAL
  {
!  $$ = lang_new_vers_pattern (NULL, "local", ldgram_vers_current_lang);
  }
  | vers_defns ';' LOCAL
  {
!  $$ = lang_new_vers_pattern ($1, "local", ldgram_vers_current_lang);
  }
  | EXTERN
  {
!  $$ = lang_new_vers_pattern (NULL, "extern", ldgram_vers_current_lang);
  }
  | vers_defns ';' EXTERN
  {
!  $$ = lang_new_vers_pattern ($1, "extern", ldgram_vers_current_lang);
  }
  ;
 
  opt_semicolon:
  /* empty */
--- 1256,1286 ----
   $$ = $5;
   ldgram_vers_current_lang = $<name>4;
  }
  | GLOBAL
  {
!  $$ = lang_new_vers_pattern (NULL, "global", ldgram_vers_current_lang, FALSE);
  }
  | vers_defns ';' GLOBAL
  {
!  $$ = lang_new_vers_pattern ($1, "global", ldgram_vers_current_lang, FALSE);
  }
  | LOCAL
  {
!  $$ = lang_new_vers_pattern (NULL, "local", ldgram_vers_current_lang, FALSE);
  }
  | vers_defns ';' LOCAL
  {
!  $$ = lang_new_vers_pattern ($1, "local", ldgram_vers_current_lang, FALSE);
  }
  | EXTERN
  {
!  $$ = lang_new_vers_pattern (NULL, "extern", ldgram_vers_current_lang, FALSE);
  }
  | vers_defns ';' EXTERN
  {
!  $$ = lang_new_vers_pattern ($1, "extern", ldgram_vers_current_lang, FALSE);
  }
  ;
 
  opt_semicolon:
  /* empty */
Index: ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.199
diff -c -5 -p -r1.199 ldlang.c
*** ldlang.c 30 Sep 2005 22:10:54 -0000 1.199
--- ldlang.c 13 Oct 2005 00:59:37 -0000
*************** lang_vers_match (struct bfd_elf_version_
*** 6220,6255 ****
  e.symbol = sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_C_TYPE)
     goto out_ret;
! else
!  expr = expr->next;
       }
     /* Fallthrough */
   case BFD_ELF_VERSION_C_TYPE:
     if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
       {
  e.symbol = cxx_sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, cxx_sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
     goto out_ret;
! else
!  expr = expr->next;
       }
     /* Fallthrough */
   case BFD_ELF_VERSION_CXX_TYPE:
     if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
       {
  e.symbol = java_sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, java_sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
     goto out_ret;
! else
!  expr = expr->next;
       }
     /* Fallthrough */
   default:
     break;
  }
--- 6220,6255 ----
  e.symbol = sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_C_TYPE)
     goto out_ret;
!  else
!    expr = expr->next;
       }
     /* Fallthrough */
   case BFD_ELF_VERSION_C_TYPE:
     if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
       {
  e.symbol = cxx_sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, cxx_sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
     goto out_ret;
!  else
!    expr = expr->next;
       }
     /* Fallthrough */
   case BFD_ELF_VERSION_CXX_TYPE:
     if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
       {
  e.symbol = java_sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, java_sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
     goto out_ret;
!  else
!    expr = expr->next;
       }
     /* Fallthrough */
   default:
     break;
  }
*************** lang_vers_match (struct bfd_elf_version_
*** 6258,6271 ****
    /* Finally, try the wildcards.  */
    if (prev == NULL || prev->symbol)
      expr = head->remaining;
    else
      expr = prev->next;
!   while (expr)
      {
        const char *s;
 
        if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
  break;
 
        if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
  s = java_sym;
--- 6258,6274 ----
    /* Finally, try the wildcards.  */
    if (prev == NULL || prev->symbol)
      expr = head->remaining;
    else
      expr = prev->next;
!   for (; expr; expr = expr->next)
      {
        const char *s;
 
+       if (!expr->pattern)
+ continue;
+
        if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
  break;
 
        if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
  s = java_sym;
*************** lang_vers_match (struct bfd_elf_version_
*** 6273,6283 ****
  s = cxx_sym;
        else
  s = sym;
        if (fnmatch (expr->pattern, s, 0) == 0)
  break;
-       expr = expr->next;
      }
 
  out_ret:
    if (cxx_sym != sym)
      free ((char *) cxx_sym);
--- 6276,6285 ----
*************** realsymbol (const char *pattern)
*** 6328,6352 ****
        free (symbol);
        return pattern;
      }
  }
 
! /* This is called for each variable name or match expression.  */
 
  struct bfd_elf_version_expr *
  lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
        const char *new,
!       const char *lang)
  {
    struct bfd_elf_version_expr *ret;
 
    ret = xmalloc (sizeof *ret);
    ret->next = orig;
!   ret->pattern = new;
    ret->symver = 0;
    ret->script = 0;
!   ret->symbol = realsymbol (new);
 
    if (lang == NULL || strcasecmp (lang, "C") == 0)
      ret->mask = BFD_ELF_VERSION_C_TYPE;
    else if (strcasecmp (lang, "C++") == 0)
      ret->mask = BFD_ELF_VERSION_CXX_TYPE;
--- 6330,6357 ----
        free (symbol);
        return pattern;
      }
  }
 
! /* This is called for each variable name or match expression.  NEW is
!    the name of the symbol to match, or, if LITERAL_P is FALSE, a glob
!    pattern to be matched against symbol names.  */
 
  struct bfd_elf_version_expr *
  lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
        const char *new,
!       const char *lang,
!       bfd_boolean literal_p)
  {
    struct bfd_elf_version_expr *ret;
 
    ret = xmalloc (sizeof *ret);
    ret->next = orig;
!   ret->pattern = literal_p ? NULL : new;
    ret->symver = 0;
    ret->script = 0;
!   ret->symbol = literal_p ? new : realsymbol (new);
 
    if (lang == NULL || strcasecmp (lang, "C") == 0)
      ret->mask = BFD_ELF_VERSION_C_TYPE;
    else if (strcasecmp (lang, "C++") == 0)
      ret->mask = BFD_ELF_VERSION_CXX_TYPE;
*************** lang_do_version_exports_section (void)
*** 6626,6646 ****
  einfo (_("%X%P: unable to read .exports section contents\n"), sec);
 
        p = contents;
        while (p < contents + len)
  {
!  greg = lang_new_vers_pattern (greg, p, NULL);
   p = strchr (p, '\0') + 1;
  }
 
        /* Do not free the contents, as we used them creating the regex.  */
 
        /* Do not include this section in the link.  */
        sec->flags |= SEC_EXCLUDE;
      }
 
!   lreg = lang_new_vers_pattern (NULL, "*", NULL);
    lang_register_vers_node (command_line.version_exports_section,
    lang_new_vers_node (greg, lreg), NULL);
  }
 
  void
--- 6631,6651 ----
  einfo (_("%X%P: unable to read .exports section contents\n"), sec);
 
        p = contents;
        while (p < contents + len)
  {
!  greg = lang_new_vers_pattern (greg, p, NULL, FALSE);
   p = strchr (p, '\0') + 1;
  }
 
        /* Do not free the contents, as we used them creating the regex.  */
 
        /* Do not include this section in the link.  */
        sec->flags |= SEC_EXCLUDE;
      }
 
!   lreg = lang_new_vers_pattern (NULL, "*", NULL, FALSE);
    lang_register_vers_node (command_line.version_exports_section,
    lang_new_vers_node (greg, lreg), NULL);
  }
 
  void
Index: ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.53
diff -c -5 -p -r1.53 ldlang.h
*** ldlang.h 30 Sep 2005 17:45:46 -0000 1.53
--- ldlang.h 13 Oct 2005 00:59:37 -0000
*************** extern void lang_leave_overlay
*** 584,594 ****
     lang_output_section_phdr_list *, const char *);
 
  extern struct bfd_elf_version_tree *lang_elf_version_info;
 
  extern struct bfd_elf_version_expr *lang_new_vers_pattern
!   (struct bfd_elf_version_expr *, const char *, const char *);
  extern struct bfd_elf_version_tree *lang_new_vers_node
    (struct bfd_elf_version_expr *, struct bfd_elf_version_expr *);
  extern struct bfd_elf_version_deps *lang_add_vers_depend
    (struct bfd_elf_version_deps *, const char *);
  extern void lang_register_vers_node
--- 584,594 ----
     lang_output_section_phdr_list *, const char *);
 
  extern struct bfd_elf_version_tree *lang_elf_version_info;
 
  extern struct bfd_elf_version_expr *lang_new_vers_pattern
!   (struct bfd_elf_version_expr *, const char *, const char *, bfd_boolean);
  extern struct bfd_elf_version_tree *lang_new_vers_node
    (struct bfd_elf_version_expr *, struct bfd_elf_version_expr *);
  extern struct bfd_elf_version_deps *lang_add_vers_depend
    (struct bfd_elf_version_deps *, const char *);
  extern void lang_register_vers_node
Index: testsuite/ld-elfvers/vers.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-elfvers/vers.exp,v
retrieving revision 1.38
diff -c -5 -p -r1.38 vers.exp
*** testsuite/ld-elfvers/vers.exp 17 Aug 2005 10:08:30 -0000 1.38
--- testsuite/ld-elfvers/vers.exp 13 Oct 2005 00:59:38 -0000
*************** build_vers_lib_pic "vers28c" vers28c.c v
*** 962,966 ****
--- 962,969 ----
  build_vers_lib_pic_flags "vers29" vers29.c vers29 "" "" vers29.ver vers29.dsym "" "--default-symver"
 
  # Test #30 - test handling of symbol names global, local and extern in the
  # version script.
  build_vers_lib_pic "vers30" vers30.c vers30 "" vers30.map vers30.ver vers30.dsym ""
+
+ # Test #31 -- quoted strings in version sections.
+ build_vers_lib_pic "vers31" vers31.c vers31 "" vers31.map vers31.ver vers31.dsym ""
Index: testsuite/ld-elfvers/vers31.c
===================================================================
RCS file: testsuite/ld-elfvers/vers31.c
diff -N testsuite/ld-elfvers/vers31.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/ld-elfvers/vers31.c 13 Oct 2005 00:59:38 -0000
***************
*** 0 ****
--- 1,6 ----
+ /* int f<int, char>(int, char) */
+ void _Z1fIicET_S0_T0_() {}
+
+ /* double f<double, long>(double, long) */
+ void _Z1fIdlET_S0_T0_() {}
+
Index: testsuite/ld-elfvers/vers31.dsym
===================================================================
RCS file: testsuite/ld-elfvers/vers31.dsym
diff -N testsuite/ld-elfvers/vers31.dsym
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/ld-elfvers/vers31.dsym 13 Oct 2005 00:59:38 -0000
***************
*** 0 ****
--- 1,2 ----
+ [0]* g    DO \*ABS\* [0]*  VERS_31.0   VERS_31.0
+ [0-9a-f]* g    DF (.text|\*ABS\*) [0-9a-f]*  VERS_31.0   _Z1fIicET_S0_T0_
Index: testsuite/ld-elfvers/vers31.map
===================================================================
RCS file: testsuite/ld-elfvers/vers31.map
diff -N testsuite/ld-elfvers/vers31.map
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/ld-elfvers/vers31.map 13 Oct 2005 00:59:38 -0000
***************
*** 0 ****
--- 1,5 ----
+ VERS_31.0 {
+   extern "C++" {
+     "int f<int, char>(int, char)";
+   };
+ };
Index: testsuite/ld-elfvers/vers31.ver
===================================================================
RCS file: testsuite/ld-elfvers/vers31.ver
diff -N testsuite/ld-elfvers/vers31.ver
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/ld-elfvers/vers31.ver 13 Oct 2005 00:59:38 -0000
***************
*** 0 ****
--- 1,3 ----
+ Version definitions:
+ 1 0x01 0x0966595f vers31.so
+ 2 0x00 0x07923ab0 VERS_31.0
Reply | Threaded
Open this post in threaded view
|

Re: PATCH: Add double-quoted version strings

Daniel Jacobowitz-2
On Wed, Oct 12, 2005 at 06:07:01PM -0700, Mark Mitchell wrote:

>
> GNU ld supports the extern "C++" syntax in version files so that you
> can specify un-mangled names for C++ identifiers.  However, at present
> its difficult to use that facility in all cases.  For example, you
> cannot specify a space in such a name, and a "*" will be interpreted
> as a wildcard character, not as the literal "*" in a demangled name
> like "f(int *)".
>
> This patch permits double-quoted strings to be used in the version
> script, with the semantics that double-quoted strings are interpreted
> literally, not as glob patterns.

I think this is a good idea - but perhaps a cautionary note is in order
that you need to match the output of the demangler precisely is in
order for the documentation.

Especially as the output of the demangler is subject to change.

--
Daniel Jacobowitz
CodeSourcery, LLC
Reply | Threaded
Open this post in threaded view
|

Re: PATCH: Add double-quoted version strings

Nick Clifton
In reply to this post by Mark Mitchell
Hi Mark,

> OK?  

Have you tested this patch ?  I am sure that you have, but it is nice to
mention that the testing was done, and which target(s) were tested.

The patch is OK, but I agree with Daniel that we ought to have a
cautionary note in the linker documentation about matching demangler
output.

Also since the point of the patch is to allow white space and globbing
meta-characters to be matched inside the version strings, I feel that
you ought to include these characters in your test case.  eg you could have:

   int * f<int [], unsigned long>(int [], unsigned long)

instead of:

   int f<int, char>(int, char)

Cheers
   Nick
Reply | Threaded
Open this post in threaded view
|

Re: PATCH: Add double-quoted version strings

Mark Mitchell
Nick Clifton wrote:
> Hi Mark,
>
>> OK?  
>
>
> Have you tested this patch ?  I am sure that you have, but it is nice to
> mention that the testing was done, and which target(s) were tested.

Sorry, I know better!

Yes, I tested it by running the ld testsuite on x86_64-unknown-linux-gnu.

I'll incorporate the other changes suggested before check-in.

Thanks,

--
Mark Mitchell
CodeSourcery, LLC
[hidden email]
(916) 791-8304
Reply | Threaded
Open this post in threaded view
|

Re: PATCH: Add double-quoted version strings

Mark Mitchell
In reply to this post by Nick Clifton
Nick Clifton wrote:
> Hi Mark,
>
>> OK?  

> The patch is OK, but I agree with Daniel that we ought to have a
> cautionary note in the linker documentation about matching demangler
> output.

Here is the patch, as checked in, incorporating your suggestions.

Thanks,

--
Mark Mitchell
CodeSourcery, LLC
[hidden email]
(916) 791-8304

2005-10-13  Mark Mitchell  <[hidden email]>

        * ld.texino: Describe double-quoted string syntax for version
        nodes.
        * ldlang.h (lang_new_vers_pattern): Add literal_p parameter.
        * ldgram.y (vers_defns): Allow NAME as well as VERS_IDENTIFIER.
        Adjust calls to lang_new_vers_pattern to pass literal_p argument.
        * ldlang.c (lang_vers_match): Fix indentation.  Do not glob-match
        version nodes without a pattern.
        (lang_new_vers_pattern): Add literal_p parameter.
        (lang_do_version_exports_section): Pass it.

2005-10-13 Mark Mitchell  <[hidden email]>

        * ld-elfvers/vers.exp: Add vers31.
        * ld-elfvers/vers31.c: New file.
        * ld-elfvers/vers31.dsym: Likewise.
        * ld-elfvers/vers31.map: Likewise.
        * ld-elfvers/vers31.ver: Likewise.

Index: ld.texinfo
===================================================================
RCS file: /cvs/src/src/ld/ld.texinfo,v
retrieving revision 1.148
diff -c -5 -p -r1.148 ld.texinfo
*** ld.texinfo 28 Sep 2005 00:34:21 -0000 1.148
--- ld.texinfo 13 Oct 2005 17:26:14 -0000
*************** VERS_1.2 @{
*** 4287,4296 ****
--- 4287,4300 ----
  foo2;
  @} VERS_1.1;
 
  VERS_2.0 @{
  bar1; bar2;
+ extern "C++" @{      
+ ns::*;
+ "int f(int, double)";
+          @}        
  @} VERS_1.2;
  @end smallexample
 
  This example version script defines three version nodes.  The first
  version node defined is @samp{VERS_1.1}; it has no other dependencies.
*************** The script binds the symbol @samp{foo1}
*** 4298,4307 ****
--- 4302,4313 ----
  a number of symbols to local scope so that they are not visible outside
  of the shared library; this is done using wildcard patterns, so that any
  symbol whose name begins with @samp{old}, @samp{original}, or @samp{new}
  is matched.  The wildcard patterns available are the same as those used
  in the shell when matching filenames (also known as ``globbing'').
+ However, if you specify the symbol name inside double quotes, then the
+ name is treated as literal, rather than as a glob pattern.
 
  Next, the version script defines node @samp{VERS_1.2}.  This node
  depends upon @samp{VERS_1.1}.  The script binds the symbol @samp{foo2}
  to the version node @samp{VERS_1.2}.
 
*************** VERSION extern "lang" @{ version-script-
*** 4407,4416 ****
--- 4413,4432 ----
  The supported @samp{lang}s are @samp{C}, @samp{C++}, and @samp{Java}.
  The linker will iterate over the list of symbols at the link time and
  demangle them according to @samp{lang} before matching them to the
  patterns specified in @samp{version-script-commands}.
 
+ Demangled names may contains spaces and other special characters.  As
+ described above, you can use a glob pattern to match demangled names,
+ or you can use a double-quoted string to match the string exactly.  In
+ the latter case, be aware that minor differences (such as differing
+ whitespace) between the version script and the demangler output will
+ cause a mismatch.  As the exact string generated by the demangler
+ might change in the future, even if the mangled name does not, you
+ should check that all of your version directives are behaving as you
+ expect when you upgrade.
+
  @node Expressions
  @section Expressions in Linker Scripts
  @cindex expressions
  @cindex arithmetic
  The syntax for expressions in the linker script language is identical to
Index: ldgram.y
===================================================================
RCS file: /cvs/src/src/ld/ldgram.y,v
retrieving revision 1.47
diff -c -5 -p -r1.47 ldgram.y
*** ldgram.y 28 Sep 2005 00:34:21 -0000 1.47
--- ldgram.y 13 Oct 2005 17:26:14 -0000
*************** vers_tag:
*** 1217,1231 ****
  ;
 
  vers_defns:
  VERS_IDENTIFIER
  {
!  $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang);
  }
  | vers_defns ';' VERS_IDENTIFIER
  {
!  $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang);
  }
  | vers_defns ';' EXTERN NAME '{'
  {
   $<name>$ = ldgram_vers_current_lang;
   ldgram_vers_current_lang = $4;
--- 1217,1239 ----
  ;
 
  vers_defns:
  VERS_IDENTIFIER
  {
!  $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang, FALSE);
! }
!         |       NAME
! {
!  $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang, TRUE);
  }
  | vers_defns ';' VERS_IDENTIFIER
  {
!  $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang, FALSE);
! }
! | vers_defns ';' NAME
! {
!  $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang, TRUE);
  }
  | vers_defns ';' EXTERN NAME '{'
  {
   $<name>$ = ldgram_vers_current_lang;
   ldgram_vers_current_lang = $4;
*************** vers_defns:
*** 1248,1278 ****
   $$ = $5;
   ldgram_vers_current_lang = $<name>4;
  }
  | GLOBAL
  {
!  $$ = lang_new_vers_pattern (NULL, "global", ldgram_vers_current_lang);
  }
  | vers_defns ';' GLOBAL
  {
!  $$ = lang_new_vers_pattern ($1, "global", ldgram_vers_current_lang);
  }
  | LOCAL
  {
!  $$ = lang_new_vers_pattern (NULL, "local", ldgram_vers_current_lang);
  }
  | vers_defns ';' LOCAL
  {
!  $$ = lang_new_vers_pattern ($1, "local", ldgram_vers_current_lang);
  }
  | EXTERN
  {
!  $$ = lang_new_vers_pattern (NULL, "extern", ldgram_vers_current_lang);
  }
  | vers_defns ';' EXTERN
  {
!  $$ = lang_new_vers_pattern ($1, "extern", ldgram_vers_current_lang);
  }
  ;
 
  opt_semicolon:
  /* empty */
--- 1256,1286 ----
   $$ = $5;
   ldgram_vers_current_lang = $<name>4;
  }
  | GLOBAL
  {
!  $$ = lang_new_vers_pattern (NULL, "global", ldgram_vers_current_lang, FALSE);
  }
  | vers_defns ';' GLOBAL
  {
!  $$ = lang_new_vers_pattern ($1, "global", ldgram_vers_current_lang, FALSE);
  }
  | LOCAL
  {
!  $$ = lang_new_vers_pattern (NULL, "local", ldgram_vers_current_lang, FALSE);
  }
  | vers_defns ';' LOCAL
  {
!  $$ = lang_new_vers_pattern ($1, "local", ldgram_vers_current_lang, FALSE);
  }
  | EXTERN
  {
!  $$ = lang_new_vers_pattern (NULL, "extern", ldgram_vers_current_lang, FALSE);
  }
  | vers_defns ';' EXTERN
  {
!  $$ = lang_new_vers_pattern ($1, "extern", ldgram_vers_current_lang, FALSE);
  }
  ;
 
  opt_semicolon:
  /* empty */
Index: ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.199
diff -c -5 -p -r1.199 ldlang.c
*** ldlang.c 30 Sep 2005 22:10:54 -0000 1.199
--- ldlang.c 13 Oct 2005 17:26:16 -0000
*************** lang_vers_match (struct bfd_elf_version_
*** 6220,6255 ****
  e.symbol = sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_C_TYPE)
     goto out_ret;
! else
!  expr = expr->next;
       }
     /* Fallthrough */
   case BFD_ELF_VERSION_C_TYPE:
     if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
       {
  e.symbol = cxx_sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, cxx_sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
     goto out_ret;
! else
!  expr = expr->next;
       }
     /* Fallthrough */
   case BFD_ELF_VERSION_CXX_TYPE:
     if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
       {
  e.symbol = java_sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, java_sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
     goto out_ret;
! else
!  expr = expr->next;
       }
     /* Fallthrough */
   default:
     break;
  }
--- 6220,6255 ----
  e.symbol = sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_C_TYPE)
     goto out_ret;
!  else
!    expr = expr->next;
       }
     /* Fallthrough */
   case BFD_ELF_VERSION_C_TYPE:
     if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
       {
  e.symbol = cxx_sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, cxx_sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
     goto out_ret;
!  else
!    expr = expr->next;
       }
     /* Fallthrough */
   case BFD_ELF_VERSION_CXX_TYPE:
     if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
       {
  e.symbol = java_sym;
  expr = htab_find (head->htab, &e);
  while (expr && strcmp (expr->symbol, java_sym) == 0)
   if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
     goto out_ret;
!  else
!    expr = expr->next;
       }
     /* Fallthrough */
   default:
     break;
  }
*************** lang_vers_match (struct bfd_elf_version_
*** 6258,6271 ****
    /* Finally, try the wildcards.  */
    if (prev == NULL || prev->symbol)
      expr = head->remaining;
    else
      expr = prev->next;
!   while (expr)
      {
        const char *s;
 
        if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
  break;
 
        if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
  s = java_sym;
--- 6258,6274 ----
    /* Finally, try the wildcards.  */
    if (prev == NULL || prev->symbol)
      expr = head->remaining;
    else
      expr = prev->next;
!   for (; expr; expr = expr->next)
      {
        const char *s;
 
+       if (!expr->pattern)
+ continue;
+
        if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
  break;
 
        if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
  s = java_sym;
*************** lang_vers_match (struct bfd_elf_version_
*** 6273,6283 ****
  s = cxx_sym;
        else
  s = sym;
        if (fnmatch (expr->pattern, s, 0) == 0)
  break;
-       expr = expr->next;
      }
 
  out_ret:
    if (cxx_sym != sym)
      free ((char *) cxx_sym);
--- 6276,6285 ----
*************** realsymbol (const char *pattern)
*** 6328,6352 ****
        free (symbol);
        return pattern;
      }
  }
 
! /* This is called for each variable name or match expression.  */
 
  struct bfd_elf_version_expr *
  lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
        const char *new,
!       const char *lang)
  {
    struct bfd_elf_version_expr *ret;
 
    ret = xmalloc (sizeof *ret);
    ret->next = orig;
!   ret->pattern = new;
    ret->symver = 0;
    ret->script = 0;
!   ret->symbol = realsymbol (new);
 
    if (lang == NULL || strcasecmp (lang, "C") == 0)
      ret->mask = BFD_ELF_VERSION_C_TYPE;
    else if (strcasecmp (lang, "C++") == 0)
      ret->mask = BFD_ELF_VERSION_CXX_TYPE;
--- 6330,6357 ----
        free (symbol);
        return pattern;
      }
  }
 
! /* This is called for each variable name or match expression.  NEW is
!    the name of the symbol to match, or, if LITERAL_P is FALSE, a glob
!    pattern to be matched against symbol names.  */
 
  struct bfd_elf_version_expr *
  lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
        const char *new,
!       const char *lang,
!       bfd_boolean literal_p)
  {
    struct bfd_elf_version_expr *ret;
 
    ret = xmalloc (sizeof *ret);
    ret->next = orig;
!   ret->pattern = literal_p ? NULL : new;
    ret->symver = 0;
    ret->script = 0;
!   ret->symbol = literal_p ? new : realsymbol (new);
 
    if (lang == NULL || strcasecmp (lang, "C") == 0)
      ret->mask = BFD_ELF_VERSION_C_TYPE;
    else if (strcasecmp (lang, "C++") == 0)
      ret->mask = BFD_ELF_VERSION_CXX_TYPE;
*************** lang_do_version_exports_section (void)
*** 6626,6646 ****
  einfo (_("%X%P: unable to read .exports section contents\n"), sec);
 
        p = contents;
        while (p < contents + len)
  {
!  greg = lang_new_vers_pattern (greg, p, NULL);
   p = strchr (p, '\0') + 1;
  }
 
        /* Do not free the contents, as we used them creating the regex.  */
 
        /* Do not include this section in the link.  */
        sec->flags |= SEC_EXCLUDE;
      }
 
!   lreg = lang_new_vers_pattern (NULL, "*", NULL);
    lang_register_vers_node (command_line.version_exports_section,
    lang_new_vers_node (greg, lreg), NULL);
  }
 
  void
--- 6631,6651 ----
  einfo (_("%X%P: unable to read .exports section contents\n"), sec);
 
        p = contents;
        while (p < contents + len)
  {
!  greg = lang_new_vers_pattern (greg, p, NULL, FALSE);
   p = strchr (p, '\0') + 1;
  }
 
        /* Do not free the contents, as we used them creating the regex.  */
 
        /* Do not include this section in the link.  */
        sec->flags |= SEC_EXCLUDE;
      }
 
!   lreg = lang_new_vers_pattern (NULL, "*", NULL, FALSE);
    lang_register_vers_node (command_line.version_exports_section,
    lang_new_vers_node (greg, lreg), NULL);
  }
 
  void
Index: ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.53
diff -c -5 -p -r1.53 ldlang.h
*** ldlang.h 30 Sep 2005 17:45:46 -0000 1.53
--- ldlang.h 13 Oct 2005 17:26:16 -0000
*************** extern void lang_leave_overlay
*** 584,594 ****
     lang_output_section_phdr_list *, const char *);
 
  extern struct bfd_elf_version_tree *lang_elf_version_info;
 
  extern struct bfd_elf_version_expr *lang_new_vers_pattern
!   (struct bfd_elf_version_expr *, const char *, const char *);
  extern struct bfd_elf_version_tree *lang_new_vers_node
    (struct bfd_elf_version_expr *, struct bfd_elf_version_expr *);
  extern struct bfd_elf_version_deps *lang_add_vers_depend
    (struct bfd_elf_version_deps *, const char *);
  extern void lang_register_vers_node
--- 584,594 ----
     lang_output_section_phdr_list *, const char *);
 
  extern struct bfd_elf_version_tree *lang_elf_version_info;
 
  extern struct bfd_elf_version_expr *lang_new_vers_pattern
!   (struct bfd_elf_version_expr *, const char *, const char *, bfd_boolean);
  extern struct bfd_elf_version_tree *lang_new_vers_node
    (struct bfd_elf_version_expr *, struct bfd_elf_version_expr *);
  extern struct bfd_elf_version_deps *lang_add_vers_depend
    (struct bfd_elf_version_deps *, const char *);
  extern void lang_register_vers_node
Index: testsuite/ld-elfvers/vers.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-elfvers/vers.exp,v
retrieving revision 1.38
diff -c -5 -p -r1.38 vers.exp
*** testsuite/ld-elfvers/vers.exp 17 Aug 2005 10:08:30 -0000 1.38
--- testsuite/ld-elfvers/vers.exp 13 Oct 2005 17:26:17 -0000
*************** build_vers_lib_pic "vers28c" vers28c.c v
*** 962,966 ****
--- 962,969 ----
  build_vers_lib_pic_flags "vers29" vers29.c vers29 "" "" vers29.ver vers29.dsym "" "--default-symver"
 
  # Test #30 - test handling of symbol names global, local and extern in the
  # version script.
  build_vers_lib_pic "vers30" vers30.c vers30 "" vers30.map vers30.ver vers30.dsym ""
+
+ # Test #31 -- quoted strings in version sections.
+ build_vers_lib_pic "vers31" vers31.c vers31 "" vers31.map vers31.ver vers31.dsym ""
Index: testsuite/ld-elfvers/vers31.c
===================================================================
RCS file: testsuite/ld-elfvers/vers31.c
diff -N testsuite/ld-elfvers/vers31.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/ld-elfvers/vers31.c 13 Oct 2005 17:26:17 -0000
***************
*** 0 ****
--- 1,6 ----
+ /* void f<int [3], char>(int (*) [3], char) */
+ void _Z1fIA3_icEvPT_T0_() {}
+
+ /* void f<double [3], long>(double (*) [3], long) */
+ void _Z1fIA3_dlEvPT_T0_() {}
+
Index: testsuite/ld-elfvers/vers31.dsym
===================================================================
RCS file: testsuite/ld-elfvers/vers31.dsym
diff -N testsuite/ld-elfvers/vers31.dsym
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/ld-elfvers/vers31.dsym 13 Oct 2005 17:26:17 -0000
***************
*** 0 ****
--- 1,2 ----
+ [0]* g    DO \*ABS\* [0]*  VERS_31.0   VERS_31.0
+ [0-9a-f]* g    DF (.text|\*ABS\*) [0-9a-f]*  VERS_31.0   _Z1fIA3_icEvPT_T0
Index: testsuite/ld-elfvers/vers31.map
===================================================================
RCS file: testsuite/ld-elfvers/vers31.map
diff -N testsuite/ld-elfvers/vers31.map
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/ld-elfvers/vers31.map 13 Oct 2005 17:26:17 -0000
***************
*** 0 ****
--- 1,5 ----
+ VERS_31.0 {
+   extern "C++" {
+     "void f<int [3], char>(int (*) [3], char)";
+   };
+ };
Index: testsuite/ld-elfvers/vers31.ver
===================================================================
RCS file: testsuite/ld-elfvers/vers31.ver
diff -N testsuite/ld-elfvers/vers31.ver
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/ld-elfvers/vers31.ver 13 Oct 2005 17:26:17 -0000
***************
*** 0 ****
--- 1,3 ----
+ Version definitions:
+ 1 0x01 0x0966595f vers31.so
+ 2 0x00 0x07923ab0 VERS_31.0