From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3766 invoked by alias); 3 Aug 2005 03:07:54 -0000 Mailing-List: contact gcc-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-owner@gcc.gnu.org Received: (qmail 3494 invoked by uid 22791); 3 Aug 2005 03:07:31 -0000 Received: from smtp110.sbc.mail.mud.yahoo.com (HELO smtp110.sbc.mail.mud.yahoo.com) (68.142.198.209) by sourceware.org (qpsmtpd/0.30-dev) with SMTP; Wed, 03 Aug 2005 03:07:31 +0000 Received: (qmail 80569 invoked from network); 3 Aug 2005 03:07:26 -0000 Received: from unknown (HELO lucon.org) (hjjean@sbcglobal.net@69.232.224.217 with login) by smtp110.sbc.mail.mud.yahoo.com with SMTP; 3 Aug 2005 03:07:24 -0000 Received: by lucon.org (Postfix, from userid 1000) id 9680064552; Tue, 2 Aug 2005 20:07:22 -0700 (PDT) Date: Wed, 03 Aug 2005 03:07:00 -0000 From: "H. J. Lu" To: michael meeks Cc: Martin Hollmichel - Sun Germany - ham02 - Hamburg , Giovanni Bajo , gcc@gcc.gnu.org Subject: PATCH: Add export to linker map (Re: Large, modular C++ application performance ...) Message-ID: <20050803030722.GA2491@lucon.org> References: <1122666555.19624.25.camel@linux.site> <019e01c5950b$a7ddff90$bf03030a@trilan> <1122889126.19623.105.camel@linux.site> <20050801155517.GA5095@lucon.org> <1122976741.25656.54.camel@linux.site> <20050802135722.GA23692@lucon.org> <1122999276.25655.125.camel@linux.site> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="oyUTqETQ0mS9luUI" Content-Disposition: inline In-Reply-To: <1122999276.25655.125.camel@linux.site> User-Agent: Mutt/1.4.1i X-Virus-Checked: Checked by ClamAV on sourceware.org X-SW-Source: 2005-08/txt/msg00100.txt.bz2 --oyUTqETQ0mS9luUI Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 2035 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. --oyUTqETQ0mS9luUI Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="binutils-version-scope-2.patch" Content-length: 60948 bfd/ 2005-08-02 H.J. Lu * 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 * 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 * 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; } @@ -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 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 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\[\]\-\!\^\\]([ local { RTOKEN(LOCAL); } +export { RTOKEN(EXPORT); } + extern { RTOKEN(EXTERN); } {V_IDENTIFIER} { yylval.name = xstrdup (yytext); --oyUTqETQ0mS9luUI--