public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
From: "H. J. Lu" <hjl@lucon.org>
To: michael meeks <michael.meeks@novell.com>
Cc: Martin Hollmichel - Sun Germany - ham02 - Hamburg
	<martin.hollmichel@Sun.COM>, Giovanni Bajo <rasky@develer.com>,
	gcc@gcc.gnu.org
Subject: PATCH: Add export to linker map (Re: Large, modular C++ application performance ...)
Date: Wed, 03 Aug 2005 03:07:00 -0000	[thread overview]
Message-ID: <20050803030722.GA2491@lucon.org> (raw)
In-Reply-To: <1122999276.25655.125.camel@linux.site>

[-- Attachment #1: Type: text/plain, Size: 2035 bytes --]

On Tue, Aug 02, 2005 at 05:14:36PM +0100, michael meeks wrote:
> 
> On Tue, 2005-08-02 at 06:57 -0700, H. J. Lu wrote:
> > Maitaining a C++ linker map isn't easy. I think gcc should help out
> > here.
> 
> 	What do you suggest ? - something separate from the visibility markup ?
> perhaps what I'm suggesting is some horribly mis-use of that. Clearly
> adding a new visibility attribute that would bind that symbol
> internally, yet export it would be a simple approach; did you have a
> better idea ? and/or suggestions for a name ? - or is this a total
> non-starter for some other reason ?

The problem is there is no bit in ELF symbol table to support new
attribute. However, we do have linker map. This patch adds the new
"export" key word. It can be used to export a symbol even if it is
hidden or it is defined in executable and not referenced by any DSOs.
The difference between "export" and "global" is exported symbol will
be resolved locally.

I think it is possible for gcc to generate linker script automatically.
It knows which symbols have to be defined once, which symbols can
be resolved locally and which symbols should exported. We can even
add new attributes for symbol versions. We don't have to maintain
linker-map.gnu by hand.

> 
> > > 	That would suit our needs beautifully - if, when used to annotate a
> > > class, it would allow the various typeinfo / vague-linkage pieces
> > > through as 'default'. Is it a realistic suggestion ? / if so, am happy
> > > to knock up a patch.
> > > 
> > > 	[ and of course, this is only 1/2 the problem - the other half isn't
> > > much helped by visibility markup as previously discussed ;-]
> >
> > Why not? If you know a symbol in DSO won't be overridden by others,
> > you can resolve it locally via a linker map.
> 
> 	Sure - the other (more than) 1/2 of the performance problem comes from
> named relocations to symbols external to the DSO.

You only need that if there has to be one and only definition. How many
symbols have to be defined once in a C++ DSO?


H.J.

[-- Attachment #2: binutils-version-scope-2.patch --]
[-- Type: text/plain, Size: 60948 bytes --]

bfd/

2005-08-02  H.J. Lu  <hongjiu.lu@intel.com>

	* elf-bfd.h (elf_link_hash_entry): Remove forced_local. Add
	scope.
	(WILL_CALL_FINISH_DYNAMIC_SYMBOL): Updated.
	* elf.c (_bfd_elf_link_hash_hide_symbol): Likewise.
	* elf32-arm.c (record_arm_to_thumb_glue): Likewise.
	(allocate_dynrelocs): Likewise.
	* elf32-cris.c (elf_cris_discard_excess_dso_dynamics):
	Likewise.
	* elf32-hppa.c (elf32_hppa_create_dynamic_sections): Likewise.
	(elf32_hppa_hide_symbol): Likewise.
	(allocate_plt_static): Likewise.
	(allocate_dynrelocs): Likewise.
	(clobber_millicode_symbols): Likewise.
	(get_local_syms): Likewise.
	* elf32-i386.c (allocate_dynrelocs): Likewise.
	* elf32-m32r.c (allocate_dynrelocs): Likewise.
	(m32r_elf_relocate_section): Likewise.
	(m32r_elf_finish_dynamic_symbol): Likewise.
	(m32r_elf_check_relocs): Likewise.
	* elf32-m68k.c (elf_m68k_check_relocs): Likewise.
	(elf_m68k_adjust_dynamic_symbol): Likewise.
	(elf_m68k_discard_copies): Likewise.
	(elf_m68k_relocate_section): Likewise.
	(elf_m68k_finish_dynamic_symbol): Likewise.
	* elf32-ppc.c (allocate_dynrelocs): Likewise.
	* elf32-s390.c (allocate_dynrelocs): Likewise.
	(elf_s390_finish_dynamic_symbol): Likewise.
	* elf32-sh.c (allocate_dynrelocs): Likewise.
	(sh_elf_relocate_section): Likewise.
	(sh_elf_check_relocs): Likewise.
	* elf64-ppc.c (func_desc_adjust): Likewise.
	(allocate_dynrelocs): Likewise.
	(ppc_build_one_stub): Likewise.
	(ppc64_elf_build_stubs): Likewise.
	* elf64-s390.c (allocate_dynrelocs): Likewise.
	(elf_s390_relocate_section): Likewise.
	(elf_s390_finish_dynamic_symbol): Likewise.
	* elf64-x86-64.c (allocate_dynrelocs): Likewise.
	* elflink.c (bfd_elf_record_link_assignment): Likewise.
	(elf_link_renumber_hash_table_dynsyms): Likewise.
	(elf_link_renumber_local_hash_table_dynsy): Likewise.
	(_bfd_elf_dynamic_symbol_p): Likewise.
	(_bfd_elf_symbol_refs_local_p): Likewise.
	(bfd_elf_size_dynamic_sections): Likewise.
	* elfxx-mips.c (mips_elf_create_local_got_entry): Likewise.
	(mips_elf_local_relocation_p): Likewise.
	(_bfd_mips_relax_section): Likewise.
	(_bfd_mips_elf_finish_dynamic_symbol): Likewise.
	* elfxx-sparc.c (allocate_dynrelocs): Likewise.
	(_bfd_sparc_elf_relocate_section): Likewise.

	* elflink.c (bfd_elf_link_record_dynamic_symbol): Don't check
	symbol visibilty on exported symbols.
	(_bfd_elf_export_symbol): Updated for exported symbols.
	(_bfd_elf_link_assign_sym_version): Likewise.
	(elf_link_output_extsym): Likewise.

include/

2005-08-02  H.J. Lu  <hongjiu.lu@intel.com>

	* bfdlink.h (bfd_elf_version_expr): Add scope.
	(BFD_ELF_VERSION_GLOBAL): New.
	(BFD_ELF_VERSION_LOCAL): New.
	(BFD_ELF_VERSION_EXPORT): New.
	(bfd_elf_version_tree): Remove globals and locals. Add
	symbols. Add scope to match.

ld/

2005-08-02  H.J. Lu  <hongjiu.lu@intel.com>

	* ldgram.y: Support EXPORT.
	* ldlex.l: Likewise.

	* ldlang.c (lang_final): Don't allow named version tag on
	executables.
	(lang_check_duplicated_version_expr): New.
	(lang_process): Call lang_check_duplicated_version_expr after
	lang_for_each_statement.
	(lang_vers_match): Check scope.
	(lang_new_vers_node): Only take one list.
	(lang_register_vers_node): Updated. Don't check local and
	global name conflicts here.
	(lang_do_version_exports_section): Updated.

	* ldlang.h (lang_new_vers_node): Updated.

--- binutils/bfd/elf-bfd.h.scope	2005-07-29 09:02:27.000000000 -0700
+++ binutils/bfd/elf-bfd.h	2005-08-02 14:27:36.507925544 -0700
@@ -153,8 +153,8 @@ struct elf_link_hash_entry
   unsigned int non_elf : 1;
   /* Symbol should be marked as hidden in the version information.  */
   unsigned int hidden : 1;
-  /* Symbol was forced to local scope due to a version script file.  */
-  unsigned int forced_local : 1;
+  /* Symbol scope according to a version script file.  */
+  unsigned int scope : 2;
   /* Symbol was marked during garbage collection.  */
   unsigned int mark : 1;
   /* Symbol is referenced by a non-GOT/non-PLT relocation.  This is
@@ -1858,8 +1858,8 @@ extern bfd_boolean _sh_elf_set_mach_from
    about initializing any .plt and .got entries in relocate_section.  */
 #define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, SHARED, H) \
   ((DYN)								\
-   && ((SHARED) || !(H)->forced_local)					\
-   && ((H)->dynindx != -1 || (H)->forced_local))
+   && ((SHARED) || (H)->scope == BFD_ELF_VERSION_GLOBAL)			\
+   && ((H)->dynindx != -1 || (H)->scope != BFD_ELF_VERSION_GLOBAL))
 
 /* This macro is to avoid lots of duplicated code in the body
    of xxx_relocate_section() in the various elfxx-xxxx.c files.  */
--- binutils/bfd/elf.c.scope	2005-07-27 08:41:14.000000000 -0700
+++ binutils/bfd/elf.c	2005-08-02 11:55:25.000000000 -0700
@@ -1489,7 +1489,7 @@ _bfd_elf_link_hash_hide_symbol (struct b
   h->needs_plt = 0;
   if (force_local)
     {
-      h->forced_local = 1;
+      h->scope = BFD_ELF_VERSION_LOCAL;
       if (h->dynindx != -1)
 	{
 	  h->dynindx = -1;
--- binutils/bfd/elf32-arm.c.scope	2005-07-08 08:42:31.000000000 -0700
+++ binutils/bfd/elf32-arm.c	2005-08-02 12:38:03.459570253 -0700
@@ -2099,7 +2099,7 @@ record_arm_to_thumb_glue (struct bfd_lin
 
   myh = (struct elf_link_hash_entry *) bh;
   myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
-  myh->forced_local = 1;
+  myh->scope = BFD_ELF_VERSION_LOCAL;
 
   free (tmp_name);
 
@@ -2159,7 +2159,7 @@ record_thumb_to_arm_glue (struct bfd_lin
   /* If we mark it 'Thumb', the disassembler will do a better job.  */
   myh = (struct elf_link_hash_entry *) bh;
   myh->type = ELF_ST_INFO (STB_LOCAL, STT_ARM_TFUNC);
-  myh->forced_local = 1;
+  myh->scope = BFD_ELF_VERSION_LOCAL;
 
   free (tmp_name);
 
@@ -5468,7 +5468,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -5548,7 +5548,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -5671,7 +5671,7 @@ allocate_dynrelocs (struct elf_link_hash
 	  /* Make sure this symbol is output as a dynamic symbol.
 	     Undefined weak syms won't yet be marked as dynamic.  */
 	  if (h->dynindx == -1
-	      && !h->forced_local)
+	      && h->scope != BFD_ELF_VERSION_LOCAL)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
--- binutils/bfd/elf32-cris.c.scope	2005-07-08 08:42:31.000000000 -0700
+++ binutils/bfd/elf32-cris.c	2005-08-02 12:39:07.082109072 -0700
@@ -3066,7 +3066,7 @@ elf_cris_discard_excess_dso_dynamics (h,
      definition for the symbolic link case, then we won't be needing
      any relocs.  */
   if (h->root.def_regular
-      && (h->root.forced_local
+      && (h->root.scope != BFD_ELF_VERSION_GLOBAL
 	  || info->symbolic))
     {
       for (s = h->pcrel_relocs_copied; s != NULL; s = s->next)
--- binutils/bfd/elf32-hppa.c.scope	2005-07-29 09:02:27.000000000 -0700
+++ binutils/bfd/elf32-hppa.c	2005-08-02 13:47:17.134296900 -0700
@@ -996,7 +996,7 @@ elf32_hppa_create_dynamic_sections (bfd 
   /* hppa-linux needs _GLOBAL_OFFSET_TABLE_ to be visible from the main
      application, because __canonicalize_funcptr_for_compare needs it.  */
   eh = elf_hash_table (info)->hgot;
-  eh->forced_local = 0;
+  eh->scope = BFD_ELF_VERSION_GLOBAL;
   eh->other = STV_DEFAULT;
   return bfd_elf_link_record_dynamic_symbol (info, eh);
 }
@@ -1697,7 +1697,7 @@ elf32_hppa_hide_symbol (struct bfd_link_
 {
   if (force_local)
     {
-      eh->forced_local = 1;
+      eh->scope = BFD_ELF_VERSION_LOCAL;
       if (eh->dynindx != -1)
 	{
 	  eh->dynindx = -1;
@@ -1880,7 +1880,7 @@ allocate_plt_static (struct elf_link_has
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (eh->dynindx == -1
-	  && !eh->forced_local
+	  && eh->scope != BFD_ELF_VERSION_LOCAL
 	  && eh->type != STT_PARISC_MILLI)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, eh))
@@ -1962,7 +1962,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (eh->dynindx == -1
-	  && !eh->forced_local
+	  && eh->scope != BFD_ELF_VERSION_LOCAL
 	  && eh->type != STT_PARISC_MILLI)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, eh))
@@ -1975,7 +1975,7 @@ allocate_dynrelocs (struct elf_link_hash
       if (htab->etab.dynamic_sections_created
 	  && (info->shared
 	      || (eh->dynindx != -1
-		  && !eh->forced_local)))
+		  && eh->scope == BFD_ELF_VERSION_GLOBAL)))
 	{
 	  htab->srelgot->size += sizeof (Elf32_External_Rela);
 	}
@@ -2033,7 +2033,7 @@ allocate_dynrelocs (struct elf_link_hash
 	  /* Make sure this symbol is output as a dynamic symbol.
 	     Undefined weak syms won't yet be marked as dynamic.  */
 	  if (eh->dynindx == -1
-	      && !eh->forced_local
+	      && eh->scope != BFD_ELF_VERSION_LOCAL
 	      && eh->type != STT_PARISC_MILLI)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, eh))
@@ -2077,7 +2077,7 @@ clobber_millicode_symbols (struct elf_li
     eh = (struct elf_link_hash_entry *) eh->root.u.i.link;
 
   if (eh->type == STT_PARISC_MILLI
-      && !eh->forced_local)
+      && eh->scope != BFD_ELF_VERSION_LOCAL)
     {
       elf32_hppa_hide_symbol (info, eh, TRUE);
     }
@@ -2640,7 +2640,7 @@ get_local_syms (bfd *output_bfd, bfd *in
 		      == output_bfd)
 		  && hh->eh.root.u.def.section->owner == input_bfd
 		  && hh->eh.def_regular
-		  && !hh->eh.forced_local
+		  && hh->eh.scope == BFD_ELF_VERSION_GLOBAL
 		  && ELF_ST_VISIBILITY (hh->eh.other) == STV_DEFAULT)
 		{
 		  asection *sec;
--- binutils/bfd/elf32-i386.c.scope	2005-07-18 09:51:56.000000000 -0700
+++ binutils/bfd/elf32-i386.c	2005-08-02 12:44:59.816110532 -0700
@@ -1535,7 +1535,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -1623,7 +1623,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -1712,7 +1712,7 @@ allocate_dynrelocs (struct elf_link_hash
 	  /* Make sure this symbol is output as a dynamic symbol.
 	     Undefined weak syms won't yet be marked as dynamic.  */
 	  if (h->dynindx == -1
-	      && !h->forced_local)
+	      && h->scope != BFD_ELF_VERSION_LOCAL)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
--- binutils/bfd/elf32-m32r.c.scope	2005-07-24 19:31:16.000000000 -0700
+++ binutils/bfd/elf32-m32r.c	2005-08-02 12:50:26.824341970 -0700
@@ -1994,7 +1994,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
          Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-          && !h->forced_local)
+          && h->scope != BFD_ELF_VERSION_LOCAL)
         {
           if (! bfd_elf_link_record_dynamic_symbol (info, h))
             return FALSE;
@@ -2053,7 +2053,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
          Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-          && !h->forced_local)
+          && h->scope != BFD_ELF_VERSION_LOCAL)
         {
           if (! bfd_elf_link_record_dynamic_symbol (info, h))
             return FALSE;
@@ -2082,7 +2082,7 @@ allocate_dynrelocs (struct elf_link_hash
   if (info->shared)
     {
       if (h->def_regular
-          && (h->forced_local
+          && (h->scope != BFD_ELF_VERSION_GLOBAL
               || info->symbolic))
         {
           struct elf_m32r_dyn_relocs **pp;
@@ -2114,7 +2114,7 @@ allocate_dynrelocs (struct elf_link_hash
           /* Make sure this symbol is output as a dynamic symbol.
              Undefined weak syms won't yet be marked as dynamic.  */
           if (h->dynindx == -1
-              && !h->forced_local)
+              && h->scope != BFD_ELF_VERSION_LOCAL)
             {
               if (! bfd_elf_link_record_dynamic_symbol (info, h))
                 return FALSE;
@@ -2625,8 +2625,8 @@ m32r_elf_relocate_section (bfd *output_b
                               || r_type == R_M32R_HI16_ULO_RELA
                               || r_type == R_M32R_HI16_SLO_RELA
                               || r_type == R_M32R_LO16_RELA)
-			          && !h->forced_local)
-                              || r_type == R_M32R_REL32
+			       && h->scope == BFD_ELF_VERSION_GLOBAL)
+			      || r_type == R_M32R_REL32
                               || r_type == R_M32R_10_PCREL_RELA
                               || r_type == R_M32R_18_PCREL_RELA
                               || r_type == R_M32R_26_PCREL_RELA)
@@ -2760,7 +2760,7 @@ m32r_elf_relocate_section (bfd *output_b
                       || (info->shared
                           && (info->symbolic
                               || h->dynindx == -1
-                              || h->forced_local)
+                              || h->scope != BFD_ELF_VERSION_GLOBAL)
                           && h->def_regular))
                     {
                       /* This is actually a static link, or it is a
@@ -2848,7 +2848,7 @@ m32r_elf_relocate_section (bfd *output_b
               if (h == NULL)
                 break;
 
-              if (h->forced_local)
+              if (h->scope != BFD_ELF_VERSION_GLOBAL)
                 break;
 
               if (h->plt.offset == (bfd_vma) -1)
@@ -3276,7 +3276,7 @@ m32r_elf_finish_dynamic_symbol (bfd *out
       if (info->shared
           && (info->symbolic
 	      || h->dynindx == -1
-	      || h->forced_local)
+	      || h->scope != BFD_ELF_VERSION_GLOBAL)
           && h->def_regular)
         {
           rela.r_info = ELF32_R_INFO (0, R_M32R_RELATIVE);
@@ -3875,7 +3875,7 @@ m32r_elf_check_relocs (bfd *abfd,
           if (h == NULL)
             continue;
 
-          if (h->forced_local)
+          if (h->scope != BFD_ELF_VERSION_GLOBAL)
             break;
 
           h->needs_plt = 1;
--- binutils/bfd/elf32-m68k.c.scope	2005-07-08 08:42:32.000000000 -0700
+++ binutils/bfd/elf32-m68k.c	2005-08-02 12:52:02.236653733 -0700
@@ -542,7 +542,7 @@ elf_m68k_check_relocs (abfd, info, sec, 
 		{
 		  /* Make sure this symbol is output as a dynamic symbol.  */
 		  if (h->dynindx == -1
-		      && !h->forced_local)
+		      && h->scope != BFD_ELF_VERSION_LOCAL)
 		    {
 		      if (!bfd_elf_link_record_dynamic_symbol (info, h))
 			return FALSE;
@@ -620,7 +620,7 @@ elf_m68k_check_relocs (abfd, info, sec, 
 
 	  /* Make sure this symbol is output as a dynamic symbol.  */
 	  if (h->dynindx == -1
-	      && !h->forced_local)
+	      && h->scope != BFD_ELF_VERSION_LOCAL)
 	    {
 	      if (!bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
@@ -998,7 +998,7 @@ elf_m68k_adjust_dynamic_symbol (info, h)
 
       /* Make sure this symbol is output as a dynamic symbol.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -1319,7 +1319,7 @@ elf_m68k_discard_copies (h, inf)
 
   if (!h->def_regular
       || (!info->symbolic
-	  && !h->forced_local))
+	  && h->scope == BFD_ELF_VERSION_GLOBAL))
     {
       if ((info->flags & DF_TEXTREL) == 0)
 	{
@@ -1464,7 +1464,7 @@ elf_m68k_relocate_section (output_bfd, i
 		    || (info->shared
 			&& (info->symbolic
 			    || h->dynindx == -1
-			    || h->forced_local)
+			    || h->scope != BFD_ELF_VERSION_GLOBAL)
 			&& h->def_regular))
 		  {
 		    /* This is actually a static link, or it is a
@@ -1601,7 +1601,7 @@ elf_m68k_relocate_section (output_bfd, i
 	case R_68K_PC32:
 	  if (h == NULL
 	      || (info->shared
-		  && h->forced_local))
+		  && h->scope != BFD_ELF_VERSION_GLOBAL))
 	    break;
 	  /* Fall through.  */
 	case R_68K_8:
@@ -1920,7 +1920,7 @@ elf_m68k_finish_dynamic_symbol (output_b
       if (info->shared
 	  && (info->symbolic
 	      || h->dynindx == -1
-	      || h->forced_local)
+	      || h->scope != BFD_ELF_VERSION_GLOBAL)
 	  && h->def_regular)
 	{
 	  rela.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
--- binutils/bfd/elf32-ppc.c.scope	2005-07-29 09:02:28.000000000 -0700
+++ binutils/bfd/elf32-ppc.c	2005-08-02 12:52:53.154281566 -0700
@@ -4224,7 +4224,7 @@ allocate_dynrelocs (struct elf_link_hash
 	  {
 	    /* Make sure this symbol is output as a dynamic symbol.  */
 	    if (h->dynindx == -1
-		&& !h->forced_local)
+		&& h->scope != BFD_ELF_VERSION_LOCAL)
 	      {
 		if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		  return FALSE;
@@ -4355,7 +4355,7 @@ allocate_dynrelocs (struct elf_link_hash
     {
       /* Make sure this symbol is output as a dynamic symbol.  */
       if (eh->elf.dynindx == -1
-	  && !eh->elf.forced_local)
+	  && eh->elf.scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf))
 	    return FALSE;
@@ -4444,7 +4444,7 @@ allocate_dynrelocs (struct elf_link_hash
 	  && eh->dyn_relocs != NULL
 	  && h->dynindx == -1
 	  && h->root.type == bfd_link_hash_undefweak
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -4463,7 +4463,7 @@ allocate_dynrelocs (struct elf_link_hash
 	  /* Make sure this symbol is output as a dynamic symbol.
 	     Undefined weak syms won't yet be marked as dynamic.  */
 	  if (h->dynindx == -1
-	      && !h->forced_local)
+	      && h->scope != BFD_ELF_VERSION_LOCAL)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
--- binutils/bfd/elf32-s390.c.scope	2005-07-08 08:42:32.000000000 -0700
+++ binutils/bfd/elf32-s390.c	2005-08-02 12:53:56.518862799 -0700
@@ -1762,7 +1762,7 @@ allocate_dynrelocs (h, inf)
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -1845,7 +1845,7 @@ allocate_dynrelocs (h, inf)
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -1923,7 +1923,7 @@ allocate_dynrelocs (h, inf)
 	  /* Make sure this symbol is output as a dynamic symbol.
 	     Undefined weak syms won't yet be marked as dynamic.  */
 	  if (h->dynindx == -1
-	      && !h->forced_local)
+	      && h->scope != BFD_ELF_VERSION_LOCAL)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
@@ -2390,7 +2390,7 @@ elf_s390_relocate_section (output_bfd, i
 		  || (info->shared
 		      && (info->symbolic
 			  || h->dynindx == -1
-			  || h->forced_local)
+			  || h->scope != BFD_ELF_VERSION_GLOBAL)
 		      && h->def_regular)
 		  || (ELF_ST_VISIBILITY (h->other)
 		      && h->root.type == bfd_link_hash_undefweak))
@@ -3247,7 +3247,7 @@ elf_s390_finish_dynamic_symbol (output_b
       if (info->shared
 	  && (info->symbolic
 	      || h->dynindx == -1
-	      || h->forced_local)
+	      || h->scope != BFD_ELF_VERSION_GLOBAL)
 	  && h->def_regular)
 	{
 	  BFD_ASSERT((h->got.offset & 1) != 0);
--- binutils/bfd/elf32-sh.c.scope	2005-07-08 08:42:32.000000000 -0700
+++ binutils/bfd/elf32-sh.c	2005-08-02 12:55:50.932050329 -0700
@@ -3991,7 +3991,7 @@ allocate_dynrelocs (struct elf_link_hash
 
   eh = (struct elf_sh_link_hash_entry *) h;
   if ((h->got.refcount > 0
-       || h->forced_local)
+       || h->scope != BFD_ELF_VERSION_GLOBAL)
       && eh->gotplt_refcount > 0)
     {
       /* The symbol has been forced local, or we have some direct got refs,
@@ -4009,7 +4009,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -4070,7 +4070,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -4108,7 +4108,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -4173,7 +4173,7 @@ allocate_dynrelocs (struct elf_link_hash
 	  /* Make sure this symbol is output as a dynamic symbol.
 	     Undefined weak syms won't yet be marked as dynamic.  */
 	  if (h->dynindx == -1
-	      && !h->forced_local)
+	      && h->scope != BFD_ELF_VERSION_LOCAL)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
@@ -4685,7 +4685,7 @@ sh_elf_relocate_section (bfd *output_bfd
 		      && ((! info->symbolic && h->dynindx != -1)
 			  || !h->def_regular)
 		      && ((r_type == R_SH_DIR32
-			   && !h->forced_local)
+			   && h->scope == BFD_ELF_VERSION_GLOBAL)
 			  || r_type == R_SH_REL32)
 		      && ((input_section->flags & SEC_ALLOC) != 0
 			  /* DWARF will emit R_SH_DIR32 relocations in its
@@ -4990,7 +4990,7 @@ sh_elf_relocate_section (bfd *output_bfd
 	     procedure linkage table.  */
 
 	  if (h == NULL
-	      || h->forced_local
+	      || h->scope != BFD_ELF_VERSION_GLOBAL
 	      || ! info->shared
 	      || info->symbolic
 	      || h->dynindx == -1
@@ -5218,7 +5218,7 @@ sh_elf_relocate_section (bfd *output_bfd
 	  if (h == NULL)
 	    goto final_link_relocate;
 
-	  if (h->forced_local)
+	  if (h->scope != BFD_ELF_VERSION_GLOBAL)
 	    goto final_link_relocate;
 
 	  if (h->plt.offset == (bfd_vma) -1)
@@ -6419,7 +6419,7 @@ sh_elf_check_relocs (bfd *abfd, struct b
 	     creating a procedure linkage table entry.  */
 
 	  if (h == NULL
-	      || h->forced_local
+	      || h->scope != BFD_ELF_VERSION_GLOBAL
 	      || ! info->shared
 	      || info->symbolic
 	      || h->dynindx == -1)
@@ -6450,7 +6450,7 @@ sh_elf_check_relocs (bfd *abfd, struct b
 	  if (h == NULL)
 	    continue;
 
-	  if (h->forced_local)
+	  if (h->scope != BFD_ELF_VERSION_GLOBAL)
 	    break;
 
 	  h->needs_plt = 1;
--- binutils/bfd/elf64-ppc.c.scope	2005-07-12 17:02:12.000000000 -0700
+++ binutils/bfd/elf64-ppc.c	2005-08-02 13:00:16.059052242 -0700
@@ -5466,7 +5466,7 @@ func_desc_adjust (struct elf_link_hash_e
 			  &fh->elf.root.u.def.value) != (bfd_vma) -1)
     {
       fh->elf.root.type = fh->oh->elf.root.type;
-      fh->elf.forced_local = 1;
+      fh->elf.scope = BFD_ELF_VERSION_LOCAL;
     }
 
   /* If this is a function code symbol, transfer dynamic linking
@@ -5524,7 +5524,7 @@ func_desc_adjust (struct elf_link_hash_e
     }
 
   if (fdh != NULL
-      && !fdh->elf.forced_local
+      && fdh->elf.scope == BFD_ELF_VERSION_GLOBAL
       && (info->shared
 	  || fdh->elf.def_dynamic
 	  || fdh->elf.ref_dynamic
@@ -5558,7 +5558,7 @@ func_desc_adjust (struct elf_link_hash_e
   force_local = (!fh->elf.def_regular
 		 || fdh == NULL
 		 || !fdh->elf.def_regular
-		 || fdh->elf.forced_local);
+		 || fdh->elf.scope == BFD_ELF_VERSION_LOCAL);
   _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local);
 
   return TRUE;
@@ -7431,7 +7431,7 @@ allocate_dynrelocs (struct elf_link_hash
 	   Undefined weak syms won't yet be marked as dynamic,
 	   nor will all TLS symbols.  */
 	if (h->dynindx == -1
-	    && !h->forced_local)
+	    && h->scope != BFD_ELF_VERSION_LOCAL)
 	  {
 	    if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	      return FALSE;
@@ -7512,7 +7512,7 @@ allocate_dynrelocs (struct elf_link_hash
 	  /* Make sure this symbol is output as a dynamic symbol.
 	     Undefined weak syms won't yet be marked as dynamic.  */
 	  if (h->dynindx == -1
-	      && !h->forced_local)
+	      && h->scope != BFD_ELF_VERSION_LOCAL)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
@@ -8241,7 +8241,7 @@ ppc_build_one_stub (struct bfd_hash_entr
 	  h->ref_regular = 1;
 	  h->def_regular = 1;
 	  h->ref_regular_nonweak = 1;
-	  h->forced_local = 1;
+	  h->scope = BFD_ELF_VERSION_LOCAL;
 	  h->non_elf = 0;
 	}
     }
@@ -9269,7 +9269,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_
 	      h->ref_regular = 1;
 	      h->def_regular = 1;
 	      h->ref_regular_nonweak = 1;
-	      h->forced_local = 1;
+	      h->scope = BFD_ELF_VERSION_LOCAL;
 	      h->non_elf = 0;
 	    }
 	}
--- binutils/bfd/elf64-s390.c.scope	2005-07-08 08:42:33.000000000 -0700
+++ binutils/bfd/elf64-s390.c	2005-08-02 13:01:31.645626597 -0700
@@ -1734,7 +1734,7 @@ allocate_dynrelocs (h, inf)
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -1817,7 +1817,7 @@ allocate_dynrelocs (h, inf)
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -1895,7 +1895,7 @@ allocate_dynrelocs (h, inf)
 	  /* Make sure this symbol is output as a dynamic symbol.
 	     Undefined weak syms won't yet be marked as dynamic.  */
 	  if (h->dynindx == -1
-	      && !h->forced_local)
+	      && h->scope != BFD_ELF_VERSION_LOCAL)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
@@ -2363,7 +2363,7 @@ elf_s390_relocate_section (output_bfd, i
 		  || (info->shared
 		      && (info->symbolic
 			  || h->dynindx == -1
-			  || h->forced_local)
+			  || h->scope != BFD_ELF_VERSION_GLOBAL)
 		      && h->def_regular)
 		  || (ELF_ST_VISIBILITY (h->other)
 		      && h->root.type == bfd_link_hash_undefweak))
@@ -3189,7 +3189,7 @@ elf_s390_finish_dynamic_symbol (output_b
       if (info->shared
 	  && (info->symbolic
 	      || h->dynindx == -1
-	      || h->forced_local)
+	      || h->scope != BFD_ELF_VERSION_GLOBAL)
 	  && h->def_regular)
 	{
 	  BFD_ASSERT((h->got.offset & 1) != 0);
--- binutils/bfd/elf64-x86-64.c.scope	2005-07-27 08:41:14.000000000 -0700
+++ binutils/bfd/elf64-x86-64.c	2005-08-02 13:01:52.829144248 -0700
@@ -1322,7 +1322,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -1390,7 +1390,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -1475,7 +1475,7 @@ allocate_dynrelocs (struct elf_link_hash
 	  /* Make sure this symbol is output as a dynamic symbol.
 	     Undefined weak syms won't yet be marked as dynamic.  */
 	  if (h->dynindx == -1
-	      && !h->forced_local)
+	      && h->scope != BFD_ELF_VERSION_LOCAL)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
--- binutils/bfd/elflink.c.scope	2005-08-01 09:14:21.000000000 -0700
+++ binutils/bfd/elflink.c	2005-08-02 19:31:25.897727179 -0700
@@ -375,22 +375,24 @@ bfd_elf_link_record_dynamic_symbol (stru
       /* XXX: The ABI draft says the linker must turn hidden and
 	 internal symbols into STB_LOCAL symbols when producing the
 	 DSO. However, if ld.so honors st_other in the dynamic table,
-	 this would not be necessary.  */
-      switch (ELF_ST_VISIBILITY (h->other))
-	{
-	case STV_INTERNAL:
-	case STV_HIDDEN:
-	  if (h->root.type != bfd_link_hash_undefined
-	      && h->root.type != bfd_link_hash_undefweak)
-	    {
-	      h->forced_local = 1;
-	      if (!elf_hash_table (info)->is_relocatable_executable)
-		return TRUE;
-	    }
+	 this would not be necessary.  Don't check symbol visibilty
+	 when we export a symbol.  */
+      if (h->scope != BFD_ELF_VERSION_EXPORT)
+	switch (ELF_ST_VISIBILITY (h->other))
+	  {
+	  case STV_INTERNAL:
+	  case STV_HIDDEN:
+	    if (h->root.type != bfd_link_hash_undefined
+		&& h->root.type != bfd_link_hash_undefweak)
+	      {
+		h->scope = BFD_ELF_VERSION_LOCAL;
+		if (!elf_hash_table (info)->is_relocatable_executable)
+		  return TRUE;
+	      }
 
-	default:
-	  break;
-	}
+	  default:
+	    break;
+	  }
 
       h->dynindx = elf_hash_table (info)->dynsymcount;
       ++elf_hash_table (info)->dynsymcount;
@@ -488,7 +490,7 @@ bfd_elf_record_link_assignment (struct b
       && h->dynindx != -1
       && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
 	  || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
-    h->forced_local = 1;
+    h->scope = BFD_ELF_VERSION_LOCAL;
 
   if ((h->def_dynamic
        || h->ref_dynamic
@@ -631,7 +633,7 @@ elf_link_renumber_hash_table_dynsyms (st
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-  if (h->forced_local)
+  if (h->scope == BFD_ELF_VERSION_LOCAL)
     return TRUE;
 
   if (h->dynindx != -1)
@@ -653,7 +655,7 @@ elf_link_renumber_local_hash_table_dynsy
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-  if (!h->forced_local)
+  if (h->scope != BFD_ELF_VERSION_LOCAL)
     return TRUE;
 
   if (h->dynindx != -1)
@@ -1589,16 +1591,20 @@ _bfd_elf_export_symbol (struct elf_link_
 
       for (t = eif->verdefs; t != NULL; t = t->next)
 	{
-	  if (t->globals.list != NULL)
+	  if (t->symbols.list != NULL)
 	    {
-	      d = (*t->match) (&t->globals, NULL, h->root.root.string);
+	      d = (*t->match) (BFD_ELF_VERSION_GLOBAL,
+			       &t->symbols, NULL, h->root.root.string);
 	      if (d != NULL)
 		goto doit;
-	    }
 
-	  if (t->locals.list != NULL)
-	    {
-	      d = (*t->match) (&t->locals, NULL, h->root.root.string);
+	      d = (*t->match) (BFD_ELF_VERSION_EXPORT,
+			       &t->symbols, NULL, h->root.root.string);
+	      if (d != NULL)
+		goto doit;
+
+	      d = (*t->match) (BFD_ELF_VERSION_LOCAL,
+			       &t->symbols, NULL, h->root.root.string);
 	      if (d != NULL)
 		return TRUE;
 	    }
@@ -1779,18 +1785,32 @@ _bfd_elf_link_assign_sym_version (struct
 	      t->used = TRUE;
 	      d = NULL;
 
-	      if (t->globals.list != NULL)
-		d = (*t->match) (&t->globals, NULL, alc);
+	      if (t->symbols.list != NULL)
+		{
+		  d = (*t->match) (BFD_ELF_VERSION_GLOBAL,
+				   &t->symbols, NULL, alc);
+		  if (d)
+		    h->scope = BFD_ELF_VERSION_GLOBAL;
+		  else
+		    {
+		      /* See if we should export this symbol.  */
+		      d = (*t->match) (BFD_ELF_VERSION_EXPORT,
+				       &t->symbols, NULL, alc);
+		      if (d)
+			h->scope = BFD_ELF_VERSION_EXPORT;
+		    }
 
-	      /* See if there is anything to force this symbol to
-		 local scope.  */
-	      if (d == NULL && t->locals.list != NULL)
-		{
-		  d = (*t->match) (&t->locals, NULL, alc);
-		  if (d != NULL
-		      && h->dynindx != -1
-		      && ! info->export_dynamic)
-		    (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+		  if (d == NULL)
+		    {
+		      /* See if there is anything to force this symbol
+			 to local scope.  */
+		      d = (*t->match) (BFD_ELF_VERSION_LOCAL,
+				       &t->symbols, NULL, alc);
+		      if (d != NULL
+			  && h->dynindx != -1
+			  && ! info->export_dynamic)
+			(*bed->elf_backend_hide_symbol) (info, h, TRUE);
+		    }
 		}
 
 	      free (alc);
@@ -1864,13 +1884,15 @@ _bfd_elf_link_assign_sym_version (struct
       local_ver = NULL;
       for (t = sinfo->verdefs; t != NULL; t = t->next)
 	{
-	  if (t->globals.list != NULL)
+	  if (t->symbols.list != NULL)
 	    {
 	      bfd_boolean matched;
+	      unsigned int scope = BFD_ELF_VERSION_GLOBAL;
 
 	      matched = FALSE;
 	      d = NULL;
-	      while ((d = (*t->match) (&t->globals, d,
+check_export:
+	      while ((d = (*t->match) (scope, &t->symbols, d,
 				       h->root.root.string)) != NULL)
 		if (d->symver)
 		  matched = TRUE;
@@ -1879,23 +1901,32 @@ _bfd_elf_link_assign_sym_version (struct
 		    /* There is a version without definition.  Make
 		       the symbol the default definition for this
 		       version.  */
+		    h->scope = scope;
 		    h->verinfo.vertree = t;
 		    local_ver = NULL;
 		    d->script = 1;
 		    break;
 		  }
+
 	      if (d != NULL)
 		break;
+
+	      if (scope == BFD_ELF_VERSION_GLOBAL)
+		{
+		  scope = BFD_ELF_VERSION_EXPORT;
+		  goto check_export;
+		}
 	      else if (matched)
-		/* There is no undefined version for this symbol. Hide the
-		   default one.  */
-		(*bed->elf_backend_hide_symbol) (info, h, TRUE);
-	    }
+		{
+
+		  /* There is no undefined version for this symbol.
+		     Hide the default one.  */
+		  (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+		}
 
-	  if (t->locals.list != NULL)
-	    {
 	      d = NULL;
-	      while ((d = (*t->match) (&t->locals, d,
+	      while ((d = (*t->match) (BFD_ELF_VERSION_LOCAL,
+				       &t->symbols, d,
 				       h->root.root.string)) != NULL)
 		{
 		  local_ver = t;
@@ -1922,6 +1953,15 @@ _bfd_elf_link_assign_sym_version (struct
 	}
     }
 
+  if (h->scope == BFD_ELF_VERSION_EXPORT)
+    {
+      /* If a symbol is marked export, we will make it a dynamic global
+	 symbol.   */
+      if (h->dynindx == -1
+	  && ! bfd_elf_link_record_dynamic_symbol (info, h))
+	return FALSE;
+    }
+
   return TRUE;
 }
 \f
@@ -2532,7 +2572,7 @@ _bfd_elf_dynamic_symbol_p (struct elf_li
   /* If it was forced local, then clearly it's not dynamic.  */
   if (h->dynindx == -1)
     return FALSE;
-  if (h->forced_local)
+  if (h->scope == BFD_ELF_VERSION_LOCAL)
     return FALSE;
 
   /* Identify the cases where name binding rules say that a
@@ -2589,8 +2629,8 @@ _bfd_elf_symbol_refs_local_p (struct elf
   else if (!h->def_regular)
     return FALSE;
 
-  /* Forced local symbols resolve locally.  */
-  if (h->forced_local)
+  /* Non-global symbols resolve locally.  */
+  if (h->scope != BFD_ELF_VERSION_GLOBAL)
     return TRUE;
 
   /* As do non-dynamic symbols.  */
@@ -5115,8 +5155,10 @@ bfd_elf_size_dynamic_sections (bfd *outp
 
       /* Make all global versions with definition.  */
       for (t = verdefs; t != NULL; t = t->next)
-	for (d = t->globals.list; d != NULL; d = d->next)
-	  if (!d->symver && d->symbol)
+	for (d = t->symbols.list; d != NULL; d = d->next)
+	  if (!d->symver
+	      && d->symbol
+	      && d->scope == BFD_ELF_VERSION_GLOBAL)
 	    {
 	      const char *verstr, *name;
 	      size_t namelen, verlen, newlen;
@@ -5180,8 +5222,10 @@ bfd_elf_size_dynamic_sections (bfd *outp
 	  /* Check if all global versions have a definition.  */
 	  all_defined = TRUE;
 	  for (t = verdefs; t != NULL; t = t->next)
-	    for (d = t->globals.list; d != NULL; d = d->next)
-	      if (!d->symver && !d->script)
+	    for (d = t->symbols.list; d != NULL; d = d->next)
+	      if (!d->symver
+		  && !d->script
+		  && d->scope == BFD_ELF_VERSION_GLOBAL)
 		{
 		  (*_bfd_error_handler)
 		    (_("%s: undefined version: %s"),
@@ -5473,8 +5517,7 @@ bfd_elf_size_dynamic_sections (bfd *outp
 
 	      def.vd_version = VER_DEF_CURRENT;
 	      def.vd_flags = 0;
-	      if (t->globals.list == NULL
-		  && t->locals.list == NULL
+	      if (t->symbols.list == NULL
 		  && ! t->used)
 		def.vd_flags |= VER_FLG_WEAK;
 	      def.vd_ndx = t->vernum + (info->create_default_symver ? 2 : 1);
@@ -6357,12 +6400,12 @@ elf_link_output_extsym (struct elf_link_
   /* Decide whether to output this symbol in this pass.  */
   if (eoinfo->localsyms)
     {
-      if (!h->forced_local)
+      if (h->scope != BFD_ELF_VERSION_LOCAL)
 	return TRUE;
     }
   else
     {
-      if (h->forced_local)
+      if (h->scope == BFD_ELF_VERSION_LOCAL)
 	return TRUE;
     }
 
@@ -6391,7 +6434,7 @@ elf_link_output_extsym (struct elf_link_
      shared libraries.  */
   if (! finfo->info->relocatable
       && (! finfo->info->shared)
-      && h->forced_local
+      && h->scope == BFD_ELF_VERSION_LOCAL
       && h->ref_dynamic
       && !h->dynamic_def
       && !h->dynamic_weak
@@ -6438,16 +6481,24 @@ elf_link_output_extsym (struct elf_link_
     strip = FALSE;
 
   /* If we're stripping it, and it's not a dynamic symbol, there's
-     nothing else to do unless it is a forced local symbol.  */
+     nothing else to do unless it is a forced local or exported
+     symbol.  */
   if (strip
       && h->dynindx == -1
-      && !h->forced_local)
+      && h->scope == BFD_ELF_VERSION_GLOBAL)
     return TRUE;
 
   sym.st_value = 0;
   sym.st_size = h->size;
   sym.st_other = h->other;
-  if (h->forced_local)
+  if (h->scope == BFD_ELF_VERSION_EXPORT)
+    {
+      /* An exported symbol has the default visibility.  */
+      sym.st_other
+	= STV_DEFAULT | (h->other & ~ ELF_ST_VISIBILITY (-1));
+      sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
+    }
+  else if (h->scope == BFD_ELF_VERSION_LOCAL)
     sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
   else if (h->root.type == bfd_link_hash_undefweak
 	   || h->root.type == bfd_link_hash_defweak)
@@ -6534,11 +6585,11 @@ elf_link_output_extsym (struct elf_link_
      symbol.  FIXME: Not calling elf_backend_finish_dynamic_symbol for
      forced local syms when non-shared is due to a historical quirk.  */
   if ((h->dynindx != -1
-       || h->forced_local)
+       || h->scope != BFD_ELF_VERSION_GLOBAL)
       && ((finfo->info->shared
 	   && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
 	       || h->root.type != bfd_link_hash_undefweak))
-	  || !h->forced_local)
+	  || h->scope == BFD_ELF_VERSION_GLOBAL)
       && elf_hash_table (finfo->info)->dynamic_sections_created)
     {
       if (! ((*bed->elf_backend_finish_dynamic_symbol)
@@ -9851,7 +9902,7 @@ bfd_elf_set_symbol (struct elf_link_hash
   h->def_regular = 1;
   h->type = STT_OBJECT;
   h->other = STV_HIDDEN | (h->other & ~ ELF_ST_VISIBILITY (-1));
-  h->forced_local = 1;
+  h->scope = BFD_ELF_VERSION_LOCAL;
 }
 
 /* Set NAME to VAL if the symbol exists and is not defined in a regular
--- binutils/bfd/elfxx-mips.c.scope	2005-08-01 09:14:22.000000000 -0700
+++ binutils/bfd/elfxx-mips.c	2005-08-02 14:03:55.823122875 -0700
@@ -2463,7 +2463,7 @@ mips_elf_create_local_got_entry (bfd *ab
      global entry then.  It doesn't matter whether an entry is local
      or global for TLS, since the dynamic linker does not
      automatically relocate TLS GOT entries.  */
-  BFD_ASSERT (h == NULL || h->root.forced_local);
+  BFD_ASSERT (h == NULL || h->root.scope != BFD_ELF_VERSION_GLOBAL);
   if (TLS_RELOC_P (r_type))
     {
       struct mips_got_entry *p;
@@ -3424,7 +3424,7 @@ mips_elf_local_relocation_p (bfd *input_
       while (h->root.root.type == bfd_link_hash_indirect
  	     || h->root.root.type == bfd_link_hash_warning)
 	h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
-      if (h->root.forced_local)
+      if (h->root.scope != BFD_ELF_VERSION_GLOBAL)
 	return TRUE;
     }
 
@@ -6077,8 +6077,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
 		  hmips->root.root.u.i.link;
 
 	      if (hmips->root.def_regular
-		  && ! (info->shared && ! info->symbolic
-			&& ! hmips->root.forced_local))
+		  && ! (info->shared
+			&& ! info->symbolic
+			&& hmips->root.scope == BFD_ELF_VERSION_GLOBAL))
 		break;
 	    }
 	  /* Fall through.  */
@@ -6327,8 +6328,9 @@ _bfd_mips_relax_section (bfd *abfd, asec
 	  if (! ((h->root.root.type == bfd_link_hash_defined
 		  || h->root.root.type == bfd_link_hash_defweak)
 		 && h->root.root.u.def.section)
-	      || (link_info->shared && ! link_info->symbolic
-		  && !h->root.forced_local))
+	      || (link_info->shared
+		  && ! link_info->symbolic
+		  && h->root.scope == BFD_ELF_VERSION_GLOBAL))
 	    continue;
 
 	  sym_sec = h->root.root.u.def.section;
@@ -7404,7 +7406,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd
     }
 
   BFD_ASSERT (h->dynindx != -1
-	      || h->forced_local);
+	      || h->scope != BFD_ELF_VERSION_GLOBAL);
 
   sgot = mips_elf_got_section (dynobj, FALSE);
   BFD_ASSERT (sgot != NULL);
--- binutils/bfd/elfxx-sparc.c.scope	2005-07-08 08:42:34.000000000 -0700
+++ binutils/bfd/elfxx-sparc.c	2005-08-02 13:06:44.830142330 -0700
@@ -1790,7 +1790,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -1874,7 +1874,7 @@ allocate_dynrelocs (struct elf_link_hash
       /* Make sure this symbol is output as a dynamic symbol.
 	 Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-	  && !h->forced_local)
+	  && h->scope != BFD_ELF_VERSION_LOCAL)
 	{
 	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 	    return FALSE;
@@ -1914,7 +1914,7 @@ allocate_dynrelocs (struct elf_link_hash
   if (info->shared)
     {
       if (h->def_regular
-	  && (h->forced_local
+	  && (h->scope != BFD_ELF_VERSION_GLOBAL
 	      || info->symbolic))
 	{
 	  struct _bfd_sparc_elf_dyn_relocs **pp;
@@ -1946,7 +1946,7 @@ allocate_dynrelocs (struct elf_link_hash
 	  /* Make sure this symbol is output as a dynamic symbol.
 	     Undefined weak syms won't yet be marked as dynamic.  */
 	  if (h->dynindx == -1
-	      && !h->forced_local)
+	      && h->scope != BFD_ELF_VERSION_LOCAL)
 	    {
 	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
@@ -2476,7 +2476,7 @@ _bfd_sparc_elf_relocate_section (bfd *ou
 		  || (info->shared
 		      && (info->symbolic
 			  || h->dynindx == -1
-			  || h->forced_local)
+			  || h->scope != BFD_ELF_VERSION_GLOBAL)
 		      && h->def_regular))
 		{
 		  /* This is actually a static link, or it is a
--- binutils/include/bfdlink.h.scope	2005-06-03 22:26:52.000000000 -0700
+++ binutils/include/bfdlink.h	2005-08-02 14:29:07.257014300 -0700
@@ -658,6 +658,11 @@ struct bfd_elf_version_expr
   unsigned int symver : 1;
   /* Defined by version script.  */
   unsigned int script : 1;
+  /* Scope.  */
+#define BFD_ELF_VERSION_GLOBAL		0
+#define BFD_ELF_VERSION_LOCAL		1
+#define BFD_ELF_VERSION_EXPORT		2
+  unsigned int scope : 2;
   /* Pattern type.  */
 #define BFD_ELF_VERSION_C_TYPE		1
 #define BFD_ELF_VERSION_CXX_TYPE	2
@@ -697,10 +702,8 @@ struct bfd_elf_version_tree
   const char *name;
   /* Version number.  */
   unsigned int vernum;
-  /* Regular expressions for global symbols in this version.  */
-  struct bfd_elf_version_expr_head globals;
-  /* Regular expressions for local symbols in this version.  */
-  struct bfd_elf_version_expr_head locals;
+  /* Regular expressions for symbols in this version.  */
+  struct bfd_elf_version_expr_head symbols;
   /* List of versions which this version depends upon.  */
   struct bfd_elf_version_deps *deps;
   /* Index of the version name.  This is used within BFD.  */
@@ -709,7 +712,7 @@ struct bfd_elf_version_tree
   int used;
   /* Matching hook.  */
   struct bfd_elf_version_expr *(*match)
-    (struct bfd_elf_version_expr_head *head,
+    (unsigned int scope, struct bfd_elf_version_expr_head *head,
      struct bfd_elf_version_expr *prev, const char *sym);
 };
 
--- binutils/ld/ldgram.y.scope	2005-07-24 19:31:17.000000000 -0700
+++ binutils/ld/ldgram.y	2005-08-02 16:05:46.664734554 -0700
@@ -149,7 +149,7 @@ static int error_index;
 %token FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL
 %token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START
 %token <name> VERS_TAG VERS_IDENTIFIER
-%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT
+%token GLOBAL LOCAL EXPORT VERSIONK INPUT_VERSION_SCRIPT
 %token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL
 %token EXCLUDE_FILE
 %type <versyms> vers_defns
@@ -1186,23 +1186,185 @@ verdep:
 vers_tag:
 		/* empty */
 		{
-		  $$ = lang_new_vers_node (NULL, NULL);
+		  $$ = lang_new_vers_node (NULL);
 		}
 	|	vers_defns ';'
 		{
-		  $$ = lang_new_vers_node ($1, NULL);
+		  struct bfd_elf_version_expr *e;
+		  for (e = $1; e != NULL; e = e->next)
+		    e->scope = BFD_ELF_VERSION_GLOBAL;
+		  $$ = lang_new_vers_node ($1);
 		}
 	|	GLOBAL ':' vers_defns ';'
 		{
-		  $$ = lang_new_vers_node ($3, NULL);
+		  struct bfd_elf_version_expr *e;
+		  for (e = $3; e != NULL; e = e->next)
+		    e->scope = BFD_ELF_VERSION_GLOBAL;
+		  $$ = lang_new_vers_node ($3);
 		}
 	|	LOCAL ':' vers_defns ';'
 		{
-		  $$ = lang_new_vers_node (NULL, $3);
+		  struct bfd_elf_version_expr *e;
+		  for (e = $3; e != NULL; e = e->next)
+		    e->scope = BFD_ELF_VERSION_LOCAL;
+		  $$ = lang_new_vers_node ($3);
+		}
+	|	EXPORT ':' vers_defns ';'
+		{
+		  struct bfd_elf_version_expr *e;
+		  for (e = $3; e != NULL; e = e->next)
+		    e->scope = BFD_ELF_VERSION_EXPORT;
+		  $$ = lang_new_vers_node ($3);
+		}
+	|	GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';' 
+		{
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_GLOBAL;
+		  *pp = $7;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_LOCAL;
+		  $$ = lang_new_vers_node ($3);
+		}
+	|	GLOBAL ':' vers_defns ';' EXPORT ':' vers_defns ';' 
+		{
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_GLOBAL;
+		  *pp = $7;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_EXPORT;
+		  $$ = lang_new_vers_node ($3);
+		}
+	|	LOCAL ':' vers_defns ';' GLOBAL ':' vers_defns ';' 
+		{
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_GLOBAL;
+		  *pp = $3;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_LOCAL;
+		  $$ = lang_new_vers_node ($7);
+		}
+	|	LOCAL ':' vers_defns ';' EXPORT':' vers_defns ';' 
+		{
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_LOCAL;
+		  *pp = $7;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_EXPORT;
+		  $$ = lang_new_vers_node ($3);
+		}
+	|	EXPORT ':' vers_defns ';' GLOBAL ':' vers_defns ';' 
+		{
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_GLOBAL;
+		  *pp = $3;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_EXPORT;
+		  $$ = lang_new_vers_node ($7);
+		}
+	|	EXPORT ':' vers_defns ';' LOCAL ':' vers_defns ';' 
+		{
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_LOCAL;
+		  *pp = $3;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_EXPORT;
+		  $$ = lang_new_vers_node ($7);
 		}
-	|	GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';'
+	|	GLOBAL ':' vers_defns ';'
+		LOCAL ':' vers_defns ';'
+		EXPORT ':' vers_defns ';'
+		{
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_GLOBAL;
+		  *pp = $7;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_LOCAL;
+		  *pp = $11;
+		  for (pp = &($11); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_EXPORT;
+		  $$ = lang_new_vers_node ($3);
+		}
+	|	GLOBAL ':' vers_defns ';'
+		EXPORT ':' vers_defns ';'
+		LOCAL ':' vers_defns ';'
+		{
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_GLOBAL;
+		  *pp = $11;
+		  for (pp = &($11); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_LOCAL;
+		  *pp = $7;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_EXPORT;
+		  $$ = lang_new_vers_node ($3);
+		}
+	|	LOCAL ':' vers_defns ';'
+		GLOBAL ':' vers_defns ';'
+		EXPORT ':' vers_defns ';'
+		{
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_GLOBAL;
+		  *pp = $3;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_LOCAL;
+		  *pp = $11;
+		  for (pp = &($11); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_EXPORT;
+		  $$ = lang_new_vers_node ($7);
+		}
+	|	LOCAL ':' vers_defns ';'
+		EXPORT ':' vers_defns ';'
+		GLOBAL ':' vers_defns ';'
 		{
-		  $$ = lang_new_vers_node ($3, $7);
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($11); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_GLOBAL;
+		  *pp = $3;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_LOCAL;
+		  *pp = $7;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_EXPORT;
+		  $$ = lang_new_vers_node ($11);
+		}
+	|	EXPORT ':' vers_defns ';'
+		LOCAL ':' vers_defns ';'
+		GLOBAL ':' vers_defns ';'
+		{
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($11); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_GLOBAL;
+		  *pp = $7;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_LOCAL;
+		  *pp = $3;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_EXPORT;
+		  $$ = lang_new_vers_node ($11);
+		}
+	|	EXPORT ':' vers_defns ';'
+		GLOBAL ':' vers_defns ';'
+		LOCAL ':' vers_defns ';'
+		{
+		  struct bfd_elf_version_expr **pp;
+		  for (pp = &($7); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_GLOBAL;
+		  *pp = $11;
+		  for (pp = &($11); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_LOCAL;
+		  *pp = $3;
+		  for (pp = &($3); *pp != NULL; pp = &(*pp)->next)
+		    (*pp)->scope = BFD_ELF_VERSION_EXPORT;
+		  $$ = lang_new_vers_node ($7);
 		}
 	;
 
--- binutils/ld/ldlang.c.scope	2005-07-29 09:02:33.000000000 -0700
+++ binutils/ld/ldlang.c	2005-08-02 19:53:19.597907274 -0700
@@ -5141,9 +5141,20 @@ lang_enter_output_section_statement (con
 void
 lang_final (void)
 {
-  lang_output_statement_type *new =
-    new_stat (lang_output_statement, stat_ptr);
+  lang_output_statement_type *new;
 
+  /* Check if version tag is valid for executable.  */
+  if (!link_info.relocatable && link_info.executable)
+    {
+      struct bfd_elf_version_tree *t;
+
+      for (t = lang_elf_version_info; t; t = t->next)
+	if (t->name [0] != '\0')
+	  einfo (_("%F%P: Invalid version tag `%s'. Only anonymous "
+		   "version tag is allowed in executable.\n"), t->name);
+    }
+
+  new = new_stat (lang_output_statement, stat_ptr);
   new->name = output_filename;
 }
 
@@ -5262,6 +5273,52 @@ lang_gc_sections (void)
     bfd_gc_sections (output_bfd, &link_info);
 }
 
+static void
+lang_check_duplicated_version_expr (void)
+{
+  /* Check the global and local match names, and make sure there
+     aren't any duplicates.  */
+  struct bfd_elf_version_tree *t1, *t2;
+  struct bfd_elf_version_expr *e1, *e2;
+
+  for (t1 = lang_elf_version_info; t1 != NULL; t1 = t1->next)
+    {
+      for (e1 = t1->symbols.list; e1 != NULL; e1 = e1->next)
+	{
+	  for (t2 = t1->next; t2 != NULL; t2 = t2->next)
+	    {
+	      if (t2->symbols.htab && e1->symbol)
+		{
+		  e2 = htab_find (t2->symbols.htab, e1);
+		  while (e2
+			 && (e1->scope == BFD_ELF_VERSION_LOCAL
+			     || e2->scope == BFD_ELF_VERSION_LOCAL)
+			 && e1->scope != e2->scope
+			 && strcmp (e1->symbol, e2->symbol) == 0)
+		    {
+		      if (e1->mask == e2->mask)
+			einfo (_("%X%P: duplicate expression `%s'"
+				 " in version information\n"), e1->symbol);
+		      e2 = e2->next;
+		    }
+		}
+	      else if (!e1->symbol)
+		for (e2 = t2->symbols.remaining;
+		     e2 != NULL;
+		     e2 = e2->next)
+		  if (e1->mask == e2->mask
+		      && (e1->scope == BFD_ELF_VERSION_LOCAL
+			  || e2->scope == BFD_ELF_VERSION_LOCAL)
+		      && e1->scope != e2->scope
+		      && strcmp (e1->pattern, e2->pattern) == 0)
+		    einfo (_("%X%P: duplicate expression `%s'"
+			     " in version information\n"),
+			   e1->pattern);
+	    }
+	}
+    }
+}
+
 void
 lang_process (void)
 {
@@ -5269,6 +5326,9 @@ lang_process (void)
 
   /* Open the output file.  */
   lang_for_each_statement (ldlang_open_output);
+
+  lang_check_duplicated_version_expr ();
+
   init_opb ();
 
   ldemul_create_output_section_statements ();
@@ -6120,7 +6180,8 @@ struct bfd_elf_version_tree *lang_elf_ve
    symbol after PREV (previously returned by lang_vers_match).  */
 
 static struct bfd_elf_version_expr *
-lang_vers_match (struct bfd_elf_version_expr_head *head,
+lang_vers_match (unsigned int scope,
+		 struct bfd_elf_version_expr_head *head,
 		 struct bfd_elf_version_expr *prev,
 		 const char *sym)
 {
@@ -6152,11 +6213,13 @@ lang_vers_match (struct bfd_elf_version_
 	      {
 		e.symbol = sym;
 		expr = htab_find (head->htab, &e);
-		while (expr && strcmp (expr->symbol, sym) == 0)
+		while (expr
+		       && expr->scope == scope
+		       && strcmp (expr->symbol, sym) == 0)
 		  if (expr->mask == BFD_ELF_VERSION_C_TYPE)
 		    goto out_ret;
-		else
-		  expr = expr->next;
+		  else
+		    expr = expr->next;
 	      }
 	    /* Fallthrough */
 	  case BFD_ELF_VERSION_C_TYPE:
@@ -6164,11 +6227,13 @@ lang_vers_match (struct bfd_elf_version_
 	      {
 		e.symbol = cxx_sym;
 		expr = htab_find (head->htab, &e);
-		while (expr && strcmp (expr->symbol, cxx_sym) == 0)
+		while (expr
+		       && expr->scope == scope
+		       && strcmp (expr->symbol, cxx_sym) == 0)
 		  if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
 		    goto out_ret;
-		else
-		  expr = expr->next;
+		  else
+		    expr = expr->next;
 	      }
 	    /* Fallthrough */
 	  case BFD_ELF_VERSION_CXX_TYPE:
@@ -6176,11 +6241,13 @@ lang_vers_match (struct bfd_elf_version_
 	      {
 		e.symbol = java_sym;
 		expr = htab_find (head->htab, &e);
-		while (expr && strcmp (expr->symbol, java_sym) == 0)
+		while (expr
+		       && expr->scope == scope
+		       && strcmp (expr->symbol, java_sym) == 0)
 		  if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
 		    goto out_ret;
-		else
-		  expr = expr->next;
+		  else
+		    expr = expr->next;
 	      }
 	    /* Fallthrough */
 	  default:
@@ -6193,10 +6260,13 @@ lang_vers_match (struct bfd_elf_version_
     expr = head->remaining;
   else
     expr = prev->next;
-  while (expr)
+  for (; expr; expr = expr->next)
     {
       const char *s;
 
+      if (expr->scope != scope)
+	continue;
+
       if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
 	break;
 
@@ -6208,7 +6278,6 @@ lang_vers_match (struct bfd_elf_version_
 	s = sym;
       if (fnmatch (expr->pattern, s, 0) == 0)
 	break;
-      expr = expr->next;
     }
 
 out_ret:
@@ -6299,14 +6368,11 @@ lang_new_vers_pattern (struct bfd_elf_ve
    expressions.  */
 
 struct bfd_elf_version_tree *
-lang_new_vers_node (struct bfd_elf_version_expr *globals,
-		    struct bfd_elf_version_expr *locals)
+lang_new_vers_node (struct bfd_elf_version_expr *symbols)
 {
   struct bfd_elf_version_tree *ret;
-
   ret = xcalloc (1, sizeof *ret);
-  ret->globals.list = globals;
-  ret->locals.list = locals;
+  ret->symbols.list = symbols;
   ret->match = lang_vers_match;
   ret->name_indx = (unsigned int) -1;
   return ret;
@@ -6421,7 +6487,6 @@ lang_register_vers_node (const char *nam
 			 struct bfd_elf_version_deps *deps)
 {
   struct bfd_elf_version_tree *t, **pp;
-  struct bfd_elf_version_expr *e1;
 
   if (name == NULL)
     name = "";
@@ -6440,64 +6505,7 @@ lang_register_vers_node (const char *nam
     if (strcmp (t->name, name) == 0)
       einfo (_("%X%P: duplicate version tag `%s'\n"), name);
 
-  lang_finalize_version_expr_head (&version->globals);
-  lang_finalize_version_expr_head (&version->locals);
-
-  /* Check the global and local match names, and make sure there
-     aren't any duplicates.  */
-
-  for (e1 = version->globals.list; e1 != NULL; e1 = e1->next)
-    {
-      for (t = lang_elf_version_info; t != NULL; t = t->next)
-	{
-	  struct bfd_elf_version_expr *e2;
-
-	  if (t->locals.htab && e1->symbol)
-	    {
-	      e2 = htab_find (t->locals.htab, e1);
-	      while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
-		{
-		  if (e1->mask == e2->mask)
-		    einfo (_("%X%P: duplicate expression `%s'"
-			     " in version information\n"), e1->symbol);
-		  e2 = e2->next;
-		}
-	    }
-	  else if (!e1->symbol)
-	    for (e2 = t->locals.remaining; e2 != NULL; e2 = e2->next)
-	      if (strcmp (e1->pattern, e2->pattern) == 0
-		  && e1->mask == e2->mask)
-		einfo (_("%X%P: duplicate expression `%s'"
-			 " in version information\n"), e1->pattern);
-	}
-    }
-
-  for (e1 = version->locals.list; e1 != NULL; e1 = e1->next)
-    {
-      for (t = lang_elf_version_info; t != NULL; t = t->next)
-	{
-	  struct bfd_elf_version_expr *e2;
-
-	  if (t->globals.htab && e1->symbol)
-	    {
-	      e2 = htab_find (t->globals.htab, e1);
-	      while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
-		{
-		  if (e1->mask == e2->mask)
-		    einfo (_("%X%P: duplicate expression `%s'"
-			     " in version information\n"),
-			   e1->symbol);
-		  e2 = e2->next;
-		}
-	    }
-	  else if (!e1->symbol)
-	    for (e2 = t->globals.remaining; e2 != NULL; e2 = e2->next)
-	      if (strcmp (e1->pattern, e2->pattern) == 0
-		  && e1->mask == e2->mask)
-		einfo (_("%X%P: duplicate expression `%s'"
-			 " in version information\n"), e1->pattern);
-	}
-    }
+  lang_finalize_version_expr_head (&version->symbols);
 
   version->deps = deps;
   version->name = name;
@@ -6572,8 +6580,16 @@ lang_do_version_exports_section (void)
     }
 
   lreg = lang_new_vers_pattern (NULL, "*", NULL);
+  lreg->scope = BFD_ELF_VERSION_LOCAL;
+  if (greg)
+    {
+      struct bfd_elf_version_expr **pp;
+      for (pp = &greg; *pp != NULL; pp = &(*pp)->next)
+	(*pp)->scope = BFD_ELF_VERSION_GLOBAL;
+      *pp = lreg;
+    }
   lang_register_vers_node (command_line.version_exports_section,
-			   lang_new_vers_node (greg, lreg), NULL);
+			   lang_new_vers_node (greg), NULL);
 }
 
 void
--- binutils/ld/ldlang.h.scope	2005-06-09 09:14:33.000000000 -0700
+++ binutils/ld/ldlang.h	2005-08-02 10:15:12.297225880 -0700
@@ -586,7 +586,7 @@ extern struct bfd_elf_version_tree *lang
 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 *);
+  (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
--- binutils/ld/ldlex.l.scope	2005-05-16 11:04:40.000000000 -0700
+++ binutils/ld/ldlex.l	2005-08-02 09:28:27.039884792 -0700
@@ -403,6 +403,8 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([
 
 <VERS_NODE>local		{ RTOKEN(LOCAL); }
 
+<VERS_NODE>export		{ RTOKEN(EXPORT); }
+
 <VERS_NODE>extern		{ RTOKEN(EXTERN); }
 
 <VERS_NODE>{V_IDENTIFIER}	{ yylval.name = xstrdup (yytext);

  reply	other threads:[~2005-08-03  3:07 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-07-29 19:49 Large, modular C++ application performance michael meeks
2005-07-29 20:19 ` Florian Weimer
2005-07-30 13:26   ` Nix
2005-07-30 13:36 ` Giovanni Bajo
2005-07-30 17:24   ` Andrew Haley
2005-08-01  9:45     ` michael meeks
2005-08-01 12:18       ` Steven Bosscher
2005-08-02  9:22         ` michael meeks
2005-08-01  9:39   ` michael meeks
2005-08-01 15:55     ` H. J. Lu
2005-08-02  9:59       ` michael meeks
2005-08-02 13:57         ` H. J. Lu
2005-08-02 16:15           ` michael meeks
2005-08-03  3:07             ` H. J. Lu [this message]
2005-08-01 16:59 ` Dan Nicolaescu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20050803030722.GA2491@lucon.org \
    --to=hjl@lucon.org \
    --cc=gcc@gcc.gnu.org \
    --cc=martin.hollmichel@Sun.COM \
    --cc=michael.meeks@novell.com \
    --cc=rasky@develer.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).