public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* Large, modular C++ application performance ...
@ 2005-07-29 19:49 michael meeks
  2005-07-29 20:19 ` Florian Weimer
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: michael meeks @ 2005-07-29 19:49 UTC (permalink / raw)
  To: gcc

Hi there,

	I've been doing a little thinking about how to improve OO.o startup
performance recently; and - well, relocation processing happens to be
the single, biggest thing that most tools flag.

	Anyhow - so I wrote up the problem, and a couple of potential
solutions / extensions / workarounds, and - being of a generally
clueless nature, was hoping to solicit instruction from those of a more
enlightened disposition.

	All input much appreciated; no doubt my terminology is irritatingly up
the creek, hopefully the sentiment will win through.

	http://go-oo.org/~michael/OOoStartup.pdf

	Two solutions are proposed - there are almost certainly more that I'm
not thinking of. I'm interested in people's views as to which approach
is best. So far the constructor hook approach seems to be the path of
least resistance.

	Thanks,

		Michael.

-- 
 michael.meeks@novell.com  <><, Pseudo Engineer, itinerant idiot

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  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-08-01 16:59 ` Large, modular C++ application performance Dan Nicolaescu
  2 siblings, 1 reply; 17+ messages in thread
From: Florian Weimer @ 2005-07-29 20:19 UTC (permalink / raw)
  To: michael.meeks; +Cc: gcc

* michael meeks:

> 	I've been doing a little thinking about how to improve OO.o startup
> performance recently; and - well, relocation processing happens to be
> the single, biggest thing that most tools flag.

Have you tried prelinking?

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-07-29 20:19 ` Florian Weimer
@ 2005-07-30 13:26   ` Nix
  0 siblings, 0 replies; 17+ messages in thread
From: Nix @ 2005-07-30 13:26 UTC (permalink / raw)
  To: Florian Weimer; +Cc: michael.meeks, gcc

On 29 Jul 2005, Florian Weimer announced authoritatively:
> * michael meeks:
> 
>> 	I've been doing a little thinking about how to improve OO.o startup
>> performance recently; and - well, relocation processing happens to be
>> the single, biggest thing that most tools flag.
> 
> Have you tried prelinking?

Prelinking is mentioned near the start of the paper and was actually
implemented with OOo (and KDE) in mind.

Alas, it's ineffective for dlopen()ed objects, and OOo dlopen()s nearly
everything. (To my mind the solution is `don't do that then; DT_NEEDED
has a purpose dammit'... certainly this is less disruptive than a change
to the C++ ABI, requiring cooperation with other vendors and a rebuild
of the entire known C++ universe yet again! But I am but an egg in these
waters.)

-- 
`Tor employs several thousand editors who they keep in dank
 subterranean editing facilities not unlike Moria' -- James Nicoll 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-07-29 19:49 Large, modular C++ application performance michael meeks
  2005-07-29 20:19 ` Florian Weimer
@ 2005-07-30 13:36 ` Giovanni Bajo
  2005-07-30 17:24   ` Andrew Haley
  2005-08-01  9:39   ` michael meeks
  2005-08-01 16:59 ` Large, modular C++ application performance Dan Nicolaescu
  2 siblings, 2 replies; 17+ messages in thread
From: Giovanni Bajo @ 2005-07-30 13:36 UTC (permalink / raw)
  To: michael.meeks; +Cc: gcc

michael meeks <michael.meeks@novell.com> wrote:

> I've been doing a little thinking about how to improve OO.o startup
> performance recently; and - well, relocation processing happens to be
> the single, biggest thing that most tools flag.
>
> Anyhow - so I wrote up the problem, and a couple of potential
> solutions / extensions / workarounds, and - being of a generally
> clueless nature, was hoping to solicit instruction from those of a more
> enlightened disposition.
>
> All input much appreciated; no doubt my terminology is irritatingly up
> the creek, hopefully the sentiment will win through.
>
> http://go-oo.org/~michael/OOoStartup.pdf
>
> Two solutions are proposed - there are almost certainly more that I'm
> not thinking of. I'm interested in people's views as to which approach
> is best. So far the constructor hook approach seems to be the path of
> least resistance.


I'm slow, but I can't understand why a careful design of the interfaces of
the dynamic libraries, together with the new -fvisibility flags, should not
be sufficient. It worked well in other scenarios
(http://gcc.gnu.org/wiki/Visibility).

IMHO, it's unreasonable to break the C++ ABI for 1 second of warm time
startup.
-- 
Giovanni Bajo

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-07-30 13:36 ` Giovanni Bajo
@ 2005-07-30 17:24   ` Andrew Haley
  2005-08-01  9:45     ` michael meeks
  2005-08-01  9:39   ` michael meeks
  1 sibling, 1 reply; 17+ messages in thread
From: Andrew Haley @ 2005-07-30 17:24 UTC (permalink / raw)
  To: Giovanni Bajo; +Cc: michael.meeks, gcc

Giovanni Bajo writes:
 > michael meeks <michael.meeks@novell.com> wrote:
 > 
 > > I've been doing a little thinking about how to improve OO.o startup
 > > performance recently; and - well, relocation processing happens to be
 > > the single, biggest thing that most tools flag.
 > >
 > > Anyhow - so I wrote up the problem, and a couple of potential
 > > solutions / extensions / workarounds, and - being of a generally
 > > clueless nature, was hoping to solicit instruction from those of a more
 > > enlightened disposition.
 > >
 > > All input much appreciated; no doubt my terminology is irritatingly up
 > > the creek, hopefully the sentiment will win through.
 > >
 > > http://go-oo.org/~michael/OOoStartup.pdf

One thing I don't understand is the formula where you write linking
time is proprortional to the log of the total number of symbols.  Does
this come from drepper's paper, or somewhere else?

Andrew.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-07-30 13:36 ` Giovanni Bajo
  2005-07-30 17:24   ` Andrew Haley
@ 2005-08-01  9:39   ` michael meeks
  2005-08-01 15:55     ` H. J. Lu
  1 sibling, 1 reply; 17+ messages in thread
From: michael meeks @ 2005-08-01  9:39 UTC (permalink / raw)
  To: Giovanni Bajo; +Cc: gcc

Hi Giovanni,

On Sat, 2005-07-30 at 15:36 +0200, Giovanni Bajo wrote:
> I'm slow, but I can't understand why a careful design of the interfaces of
> the dynamic libraries

	Well - sure, depends how 'careful' you are ;-) clearly if no C++
classes with virtual methods form the interface of any library, then
there is no problem ;-) unfortunately, mandating that would rather
cripple C++.

>  together with the new -fvisibility flags, should not
> be sufficient. It worked well in other scenarios

	-fvisibility is helpful - as the paper says, not as helpful as the old
-Bsymbolic (or link maps exposing only 3 or so functions) were. However
- -fvisibility can only help so much - if you have:

class LibraryAClass {
	virtual void doFoo(void);
};
class LibraryBClass : public LibraryAClass {
	virtual void doBaa(void);
};

	then there are 2 problems:

	a) there is no symbol visibility that will trigger internal
	   binding in addition to a symbol export. ie. if 
	   'LibraryBClass' is a public interface - no useful
	   visibility markup can be done; and hence we have a named
	   relocation for 'doBaa's vtable slot.
	   [ IMHO this is a feature-gap, we need a new ('export'?)
	     visibility attribute for this case ].

	b) even if LibraryBClass is a 'hidden' class - to build it's
	   vtable we have to have a slot for 'doFoo' which is in
	   an external library (A) => another named relocation. An 
	   unavoidable consequence of using virtual classes as part of
	   a library's API.

> IMHO, it's unreasonable to break the C++ ABI for 1 second of warm time
> startup.

	Well - it's an option that was considered, although - as you say -
highly unpleasant, and probably quite unnecessary - as the paper
explains.

	Regards,

		Michael.

-- 
 michael.meeks@novell.com  <><, Pseudo Engineer, itinerant idiot

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-07-30 17:24   ` Andrew Haley
@ 2005-08-01  9:45     ` michael meeks
  2005-08-01 12:18       ` Steven Bosscher
  0 siblings, 1 reply; 17+ messages in thread
From: michael meeks @ 2005-08-01  9:45 UTC (permalink / raw)
  To: Andrew Haley; +Cc: Giovanni Bajo, gcc


On Sat, 2005-07-30 at 18:25 +0100, Andrew Haley wrote:
>  > > All input much appreciated; no doubt my terminology is irritatingly up
>  > > the creek, hopefully the sentiment will win through.
>  > >
>  > > http://go-oo.org/~michael/OOoStartup.pdf
> 
> One thing I don't understand is the formula where you write linking
> time is proprortional to the log of the total number of symbols.  Does
> this come from drepper's paper, or somewhere else?

	I defer to Ulrich's text:
		http://people.redhat.com/drepper/dsohowto.pdf

	Section 1.5 of:

	"Deficiencies in the ELF hash table function and various ELF extensions
modifying the symbol lookup functionality may well increase the factor
to O(R + r.n.log(s)) where s is the number of symbols. This should make
clear that for improved performance it is significant to reduce the
number of relocations and symbols as much as possible".

	However - the log(s) term is rather irrelevant to my argument :-)

	HTH,

		Michael.

-- 
 michael.meeks@novell.com  <><, Pseudo Engineer, itinerant idiot

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-08-01  9:45     ` michael meeks
@ 2005-08-01 12:18       ` Steven Bosscher
  2005-08-02  9:22         ` michael meeks
  0 siblings, 1 reply; 17+ messages in thread
From: Steven Bosscher @ 2005-08-01 12:18 UTC (permalink / raw)
  To: gcc, michael.meeks; +Cc: Andrew Haley, Giovanni Bajo

On Monday 01 August 2005 11:44, michael meeks wrote:
> 	However - the log(s) term is rather irrelevant to my argument :-)

Not really.  Maybe the oprofile results for the linker show that the
behavior is worse, or maybe better - who knows :-)
Have you looked at any profiles btw?  Just for the curious...

Gr.
Steven

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-08-01  9:39   ` michael meeks
@ 2005-08-01 15:55     ` H. J. Lu
  2005-08-02  9:59       ` michael meeks
  0 siblings, 1 reply; 17+ messages in thread
From: H. J. Lu @ 2005-08-01 15:55 UTC (permalink / raw)
  To: michael meeks; +Cc: Giovanni Bajo, gcc

On Mon, Aug 01, 2005 at 10:38:46AM +0100, michael meeks wrote:
> Hi Giovanni,
> 
> On Sat, 2005-07-30 at 15:36 +0200, Giovanni Bajo wrote:
> > I'm slow, but I can't understand why a careful design of the interfaces of
> > the dynamic libraries
> 
> 	Well - sure, depends how 'careful' you are ;-) clearly if no C++
> classes with virtual methods form the interface of any library, then
> there is no problem ;-) unfortunately, mandating that would rather
> cripple C++.
> 
> >  together with the new -fvisibility flags, should not
> > be sufficient. It worked well in other scenarios
> 
> 	-fvisibility is helpful - as the paper says, not as helpful as the old
> -Bsymbolic (or link maps exposing only 3 or so functions) were. However
> - -fvisibility can only help so much - if you have:
> 

Since you were comparing Windows vs. ELF, doesn't Windows need a file
to define which symbols to export for a shared library? Why can't you
you do it with ELF using a linker map? Libstdc++.so is built with
a linker map. Any C++ shared library should use one if the startup
time is a big concern. Of coursee, if gcc can generate a list of
symbols suitable for linker map, which needs to be exported, it will
be very helpful. I don't think it will be too hard to implement.


H.J.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-07-29 19:49 Large, modular C++ application performance michael meeks
  2005-07-29 20:19 ` Florian Weimer
  2005-07-30 13:36 ` Giovanni Bajo
@ 2005-08-01 16:59 ` Dan Nicolaescu
  2 siblings, 0 replies; 17+ messages in thread
From: Dan Nicolaescu @ 2005-08-01 16:59 UTC (permalink / raw)
  To: michael.meeks; +Cc: gcc

michael meeks <michael.meeks@novell.com> writes:

  > Hi there,
  > 
  > 	I've been doing a little thinking about how to improve OO.o startup
  > performance recently; and - well, relocation processing happens to be
  > the single, biggest thing that most tools flag.

Have you tried eliminating all the unneeded shared libraries linked to
all the OO.o binaries and shared libraries? This should have an impact on
startup time.

ldd -u -r BINARY_OR_SHARED_LIBRARY 
should not print anything 

(as a side note Gnome is a much bigger offender on linking way too
many unused shared libraries...)

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-08-01 12:18       ` Steven Bosscher
@ 2005-08-02  9:22         ` michael meeks
  0 siblings, 0 replies; 17+ messages in thread
From: michael meeks @ 2005-08-02  9:22 UTC (permalink / raw)
  To: Steven Bosscher; +Cc: gcc, Andrew Haley, Giovanni Bajo


On Mon, 2005-08-01 at 14:18 +0200, Steven Bosscher wrote:
> On Monday 01 August 2005 11:44, michael meeks wrote:
> > 	However - the log(s) term is rather irrelevant to my argument :-)
> 
> Not really.  Maybe the oprofile results for the linker show that the
> behavior is worse, or maybe better - who knows :-)
> Have you looked at any profiles btw?  Just for the curious...

	Yes - identifying the linker and relocation processing as the root
cause of the problem isn't just a stab in the dark :-)

	This flgas up as the no.1 (individual) performance killer with whatever
profiling tools you use eg.:

	* vtune
	* speedprof
	* instrumenting top/tail of dlopen calls

	etc. :-)

	Regards,

		Michael.

-- 
 michael.meeks@novell.com  <><, Pseudo Engineer, itinerant idiot

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-08-01 15:55     ` H. J. Lu
@ 2005-08-02  9:59       ` michael meeks
  2005-08-02 13:57         ` H. J. Lu
  0 siblings, 1 reply; 17+ messages in thread
From: michael meeks @ 2005-08-02  9:59 UTC (permalink / raw)
  To: H. J. Lu
  Cc: Martin Hollmichel - Sun Germany - ham02 - Hamburg, Giovanni Bajo, gcc

Hi H.J.,

On Mon, 2005-08-01 at 08:55 -0700, H. J. Lu wrote:
> > 	-fvisibility is helpful - as the paper says, not as helpful as the old
> > -Bsymbolic (or link maps exposing only 3 or so functions) were. However
> > - -fvisibility can only help so much - if you have:
>
> Since you were comparing Windows vs. ELF, doesn't Windows need a file
> to define which symbols to export for a shared library ?

	Apparently so - here is my (fragementary) understanding of that -
Martin - please do correct me. OO.o builds the .defs on Win32 with a
custom tool called 'ldump4'. That (interestingly) goes groping in some
binary file format, reads the symbol table, groks symbols tagged with
'EXPORT:', and builds a .def file. ie. it *looks* like it's automated,
and can uses the API marked (__dllexport etc.) where appropriate.

>  Why can't you you do it with ELF using a linker map? Libstdc++.so is
> built with a linker map. Any C++ shared library should use one if the
> startup time is a big concern. Of coursee, if gcc can generate a list
> of symbols suitable for linker map, which needs to be exported, it will
> be very helpful. I don't think it will be too hard to implement.

	So - the thing about linker maps (cf. the ldump4 tool) is that they
tend to be hard to maintain, not portable across platforms, a source of
grief and problems etc. ;-) [ we have several strata of old, now defunct
link maps lying around from previous investments of effort that
subsequently became useless ].

	As I recall, I saw a suggestion (from you I think), for a new
visibility attribute 'export' or somesuch, that would resolve names
internally to the library, while still exporting the symbols.

	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 ;-]

	Thanks,

		Michael.

-- 
 michael.meeks@novell.com  <><, Pseudo Engineer, itinerant idiot

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-08-02  9:59       ` michael meeks
@ 2005-08-02 13:57         ` H. J. Lu
  2005-08-02 16:15           ` michael meeks
  0 siblings, 1 reply; 17+ messages in thread
From: H. J. Lu @ 2005-08-02 13:57 UTC (permalink / raw)
  To: michael meeks
  Cc: Martin Hollmichel - Sun Germany - ham02 - Hamburg, Giovanni Bajo, gcc

On Tue, Aug 02, 2005 at 10:59:01AM +0100, michael meeks wrote:
> Hi H.J.,
> 
> >  Why can't you you do it with ELF using a linker map? Libstdc++.so is
> > built with a linker map. Any C++ shared library should use one if the
> > startup time is a big concern. Of coursee, if gcc can generate a list
> > of symbols suitable for linker map, which needs to be exported, it will
> > be very helpful. I don't think it will be too hard to implement.
> 
> 	So - the thing about linker maps (cf. the ldump4 tool) is that they
> tend to be hard to maintain, not portable across platforms, a source of
> grief and problems etc. ;-) [ we have several strata of old, now defunct
> link maps lying around from previous investments of effort that
> subsequently became useless ].

Maitaining a C++ linker map isn't easy. I think gcc should help out
here.

> 
> 	As I recall, I saw a suggestion (from you I think), for a new
> visibility attribute 'export' or somesuch, that would resolve names
> internally to the library, while still exporting the symbols.

I sugggested the "export" visibility to export a symbol from an
executable, even if it wasn't used by any DSOs.

> 
> 	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.



H.J.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Large, modular C++ application performance ...
  2005-08-02 13:57         ` H. J. Lu
@ 2005-08-02 16:15           ` michael meeks
  2005-08-03  3:07             ` PATCH: Add export to linker map (Re: Large, modular C++ application performance ...) H. J. Lu
  0 siblings, 1 reply; 17+ messages in thread
From: michael meeks @ 2005-08-02 16:15 UTC (permalink / raw)
  To: H. J. Lu
  Cc: Martin Hollmichel - Sun Germany - ham02 - Hamburg, Giovanni Bajo, gcc


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 ?

> > 	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.

	Thanks,

		Michael.

-- 
 michael.meeks@novell.com  <><, Pseudo Engineer, itinerant idiot

^ permalink raw reply	[flat|nested] 17+ messages in thread

* PATCH: Add export to linker map (Re: Large, modular C++ application performance ...)
  2005-08-02 16:15           ` michael meeks
@ 2005-08-03  3:07             ` H. J. Lu
  0 siblings, 0 replies; 17+ messages in thread
From: H. J. Lu @ 2005-08-03  3:07 UTC (permalink / raw)
  To: michael meeks
  Cc: Martin Hollmichel - Sun Germany - ham02 - Hamburg, Giovanni Bajo, gcc

[-- 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);

^ permalink raw reply	[flat|nested] 17+ messages in thread

* re: Large, modular C++ application performance ...
  2005-07-30 15:19 dank
@ 2005-08-01  9:53 ` michael meeks
  0 siblings, 0 replies; 17+ messages in thread
From: michael meeks @ 2005-08-01  9:53 UTC (permalink / raw)
  To: dank; +Cc: gcc

Hi Dan,

On Sat, 2005-07-30 at 11:19 -0400, dank@kegel.com wrote:
> MM wrote in http://go-oo.org/~michael/OOoStartup.pdf:
> "... not one slot was overridden by an implementation
> method external to the implementing library."

	This is really an issue rather orthogonal to that of 'final', what I'm
trying to say (clearly, rather badly) - is that in those 3 libraries
there were 0 instances of virtual functions of a given class implemented
in that DSO, being implemented outside that DSO.[1]

	The significance of this is that - if we can markup classes to generate
internal relocations for their overridden slots, and copy the parent
library's (also internally) relocated version for inherited slots,
(during this proposed idle vtable relocation process). Then we would
avoid needing ~any named relocations at all to construct these vtables.
ie. go from many tens of thousands of the slowest type of relocation, to
none.

	HTH,

		Michael.

[1] - further research AFAIR showed only a handful of these instances
across all OO.o libraries.
-- 
 michael.meeks@novell.com  <><, Pseudo Engineer, itinerant idiot

^ permalink raw reply	[flat|nested] 17+ messages in thread

* re: Large, modular C++ application performance ...
@ 2005-07-30 15:19 dank
  2005-08-01  9:53 ` michael meeks
  0 siblings, 1 reply; 17+ messages in thread
From: dank @ 2005-07-30 15:19 UTC (permalink / raw)
  To: gcc; +Cc: michael.meeks

MM wrote in http://go-oo.org/~michael/OOoStartup.pdf:
"... not one slot was overridden by an implementation
method external to the implementing library."

Hmm.  For some reason that reminds me of the 'final'
keyword which is periodically proposed
(e.g. http://gcc.gnu.org/ml/gcc/2004-02/msg01483.html).
Is this a situation where 'final' would have a benefit?

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2005-08-03  3:07 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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             ` PATCH: Add export to linker map (Re: Large, modular C++ application performance ...) H. J. Lu
2005-08-01 16:59 ` Large, modular C++ application performance Dan Nicolaescu
2005-07-30 15:19 dank
2005-08-01  9:53 ` michael meeks

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).