From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29795 invoked by alias); 30 Jun 2012 21:19:03 -0000 Received: (qmail 29773 invoked by uid 22791); 30 Jun 2012 21:18:59 -0000 X-SWARE-Spam-Status: No, hits=-3.5 required=5.0 tests=AWL,BAYES_00,FSL_FREEMAIL_1,KAM_STOCKGEN,KHOP_RCVD_UNTRUST,NO_DNS_FOR_FROM,RCVD_IN_DNSWL_HI,RCVD_IN_HOSTKARMA_W,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mga02.intel.com (HELO mga02.intel.com) (134.134.136.20) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 30 Jun 2012 21:18:42 +0000 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga101.jf.intel.com with ESMTP; 30 Jun 2012 14:18:42 -0700 X-ExtLoop1: 1 Received: from gnu-6.sc.intel.com ([10.3.194.135]) by orsmga001.jf.intel.com with ESMTP; 30 Jun 2012 14:18:41 -0700 Received: by gnu-6.sc.intel.com (Postfix, from userid 500) id 871C3800CC; Sat, 30 Jun 2012 14:18:41 -0700 (PDT) Date: Sat, 30 Jun 2012 21:19:00 -0000 From: "H.J. Lu" To: binutils@sourceware.org Cc: GNU C Library Subject: PATCH: Add STB_SECONDARY support Message-ID: <20120630211841.GA4159@intel.com> Reply-To: "H.J. Lu" MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org X-SW-Source: 2012-06/txt/msg00282.txt.bz2 Hi, This patch adds STB_SECONDARY support. I am enclosing the STB_SECONDARY proposal posted on the gABI group. This patch is backward compatible with existing ld.so. STB_SECONDARY symbols are generated only with "ld -shared -z secondary" switch. OK to install? I will post a separate patch for glibc. Thanks. H.J. ---- We want to provide a relocatable object which can take advantage of all versions of a supported OS. For a function, foo, in the C library, we can use it only if it is available on all versions of the C library or we provide our own implementation of foo. With our own foo, the one in the C library will never be used. Here is a proposal to add STB_SECONDARY to gABI to support the secondary definition so that a software vendor can provide an alternative implementation in case it isn't available in the C library. STB_SECONDARY Secondary symbols are similar to weak symbols, but their definitions have lower precedence than global and weak symbols. The difference between secondary symbols and weak symbols are 1. The link editor ignores the secondary definition if there is a global, weak or common definition with the same name. Multiple secondary definitions with the same name will not cause an error. The first appearance of the secondary definition should be honored and the rest are ignored. 2. The link editor must search archive library and extract archive members to resolve defined and undefined secondary symbol. 3. When the link editor searches a shared object, it must honor the global or weak definition in the shared object and ignore the secondary one with the same name. 4. The link editor may treat the secondary definition in the shared object as a global definition. The purpose of this symbol binding is to provide the primary definition as a global, weak or common symbol in an archive library or a shared object while keeping a secondary definition in a relocatable object. If there is no primary definition, the secondary definition will be used. When secondary definitions become part of an executable or shared object, the link editor may convert them to global or local definitions. At run-time, when resolving a symbol, after seeing a secondary definition, the dynamic linker must keep searching until a global or weak definition is found. If a global or weak definition is found, it will be used to satisfy the symbol lookup. Otherwise, the secondary definition will be used. If the dlopen loads a global or weak definition after the program has already resolved references to a secondary definition, those references remain bound to the secondary definition. Any references resolved after the dlopen, for which the dlopened module is included in the module search list, would be resolved to the global or weak definition. STB_SECONDARY is defined as: #define STB_SECONDARY 3 /* Secondary symbol */ NOTE: The behavior of secondary symbols in areas not specified by this proposal is implementation defined. bfd/ 2012-06-30 H.J. Lu * elflink.c (_bfd_elf_merge_symbol): Allow overriding secondary symbols. (elf_link_add_object_symbols): Treat secondary symbols as weak symbols. Allow overriding secondary symbols. (elf_link_add_archive_symbols): Keep searching if a definition is secondary. (elf_link_output_extsym): Generate STB_SECONDARY symbols if needed. Treat undefined secondary symbols as weak symbols. * linker.c (_bfd_generic_link_add_one_symbol): Treat secondary symbol as weak symbol. Mark secondary symbol. 2012-06-30 H.J. Lu * archive.c (_bfd_compute_and_write_armap): Treat BSF_SECONDARY symbol as global. * elf32-mips.c (mips_elf_sym_is_global): Likewise. * elfn32-mips.c (mips_elf_sym_is_global): Likewise. * elf.c (sym_is_global): Likewise. (swap_out_syms): Handle SECONDARY symbol. * elf64-ia64-vms.c (elf64_vms_link_add_object_symbols): Likewise. * elfcode.h (elf_slurp_symbol_table): Likewise. * elflink.c (elf_link_add_object_symbols): Likewise. * syms.c (BSF_SECONDARY): New. (bfd_print_symbol_vandf): Handle SECONDARY symbol. (bfd_decode_symclass): Likewise. * bfd-in2.h: Regenerated. binutils/ 2012-06-30 H.J. Lu * nm.c (filter_symbols): Treat BSF_SECONDARY symbol as global. * readelf.c (get_symbol_binding): Handle STB_SECONDARY. gas/ 2012-06-30 H.J. Lu * symbols.c (S_IS_SECONDARY): New. (S_SET_SECONDARY): Likewise. (S_FORCE_RELOC): Handle BSF_SECONDARY like BSF_WEAK. (S_SET_EXTERNAL): Likewise. (S_CLEAR_EXTERNAL): Likewise. (S_CLEAR_WEAKREFD): Likewise. (S_SET_WEAK): Also clear BSF_SECONDARY. * symbols.h (S_IS_SECONDARY): New. (S_SET_SECONDARY): Likewise. * config/obj-elf.c (obj_elf_secondary): New. (elf_pseudo_table): Add "secondary". (elf_frob_symbol): Handle secondary symbol for .symver. Remove the unused secondary symbol. Check secondary symbols. * doc/as.texinfo: Document .secondary directive. gas/testsuite/ 2012-06-30 H.J. Lu * gas/elf/common3.d: New file. * gas/elf/common3.l: Likewise. * gas/elf/common3.s: Likewise. * gas/elf/common4.d: Likewise. * gas/elf/common4.l: Likewise. * gas/elf/common4.s: Likewise. * gas/elf/elf.exp: Run common3 and common4. * gas/elf/type.s: Add .secondary tests. * gas/elf/type.e: Updated. include/ 2012-06-30 H.J. Lu * bfdlink.h (bfd_link_hash_entry): Add secondary. (bfd_link_info): Add emit_secondary. include/elf/ 2012-06-30 H.J. Lu * common.h (STB_SECONDARY): New. ld/ 2012-06-30 H.J. Lu * ld.texinfo: Document "-z secondary". * emultempl/elf32.em (gld${EMULATION_NAME}_handle_option): Set to link_info.emit_secondary to TRUE for "-z secondary". (gld${EMULATION_NAME}_list_options): Add "-z secondary". ld/testsuite/ 2012-06-30 H.J. Lu * ld-elf/library1.c: New file. * ld-elf/library1.out: Likewise. * ld-elf/library2.c: Likewise. * ld-elf/library2.out: Likewise. * ld-elf/library3.out: Likewise. * ld-elf/library4.out: Likewise. * ld-elf/secondary-main.c: Likewise. * ld-elf/secondary.c: Likewise. * ld-elf/secondary.exp: Likewise. * ld-elf/secondary1.out: Likewise. diff --git a/bfd/archive.c b/bfd/archive.c index 0620452..f7f4134 100644 --- a/bfd/archive.c +++ b/bfd/archive.c @@ -2316,6 +2316,7 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) if (((flags & (BSF_GLOBAL | BSF_WEAK + | BSF_SECONDARY | BSF_INDIRECT | BSF_GNU_UNIQUE)) != 0 || bfd_is_com_section (sec)) diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 11f3e49..aef27f4 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -5371,6 +5371,10 @@ typedef struct bfd_symbol with this name and type in use. BSF_OBJECT must also be set. */ #define BSF_GNU_UNIQUE (1 << 23) + /* A secondary global symbol, overridable without warnings by + a regular or weak global symbol of the same name. */ +#define BSF_SECONDARY (1 << 24) + flagword flags; /* A pointer to the section to which this symbol is diff --git a/bfd/elf.c b/bfd/elf.c index 1a53548..ecbf727 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -3251,7 +3251,10 @@ sym_is_global (bfd *abfd, asymbol *sym) if (bed->elf_backend_sym_is_global) return (*bed->elf_backend_sym_is_global) (abfd, sym); - return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0 + return ((sym->flags & (BSF_GLOBAL + | BSF_WEAK + | BSF_SECONDARY + | BSF_GNU_UNIQUE)) != 0 || bfd_is_und_section (bfd_get_section (sym)) || bfd_is_com_section (bfd_get_section (sym))); } @@ -6837,8 +6840,9 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"), #endif sym.st_info = ELF_ST_INFO (STB_GLOBAL, type); } + /* Output undefined secondary symbols as weak. */ else if (bfd_is_und_section (syms[idx]->section)) - sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK) + sym.st_info = ELF_ST_INFO (((flags & (BSF_WEAK | BSF_SECONDARY)) ? STB_WEAK : STB_GLOBAL), type); @@ -6852,6 +6856,8 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"), bind = STB_LOCAL; else if (flags & BSF_GNU_UNIQUE) bind = STB_GNU_UNIQUE; + else if (flags & BSF_SECONDARY) + bind = STB_SECONDARY; else if (flags & BSF_WEAK) bind = STB_WEAK; else if (flags & BSF_GLOBAL) diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index 61e8b45..ab4ffdc 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -2133,7 +2133,10 @@ mips_elf_sym_is_global (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym) if (SGI_COMPAT (abfd)) return (sym->flags & BSF_SECTION_SYM) == 0; else - return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0 + return ((sym->flags & (BSF_GLOBAL + | BSF_WEAK + | BSF_SECONDARY + | BSF_GNU_UNIQUE)) != 0 || bfd_is_und_section (bfd_get_section (sym)) || bfd_is_com_section (bfd_get_section (sym))); } diff --git a/bfd/elf64-ia64-vms.c b/bfd/elf64-ia64-vms.c index ef78374..f37903e 100644 --- a/bfd/elf64-ia64-vms.c +++ b/bfd/elf64-ia64-vms.c @@ -4921,6 +4921,10 @@ error_free_dyn: flags = BSF_WEAK; break; + case STB_SECONDARY: + flags = BSF_SECONDARY; + break; + case STB_GNU_UNIQUE: flags = BSF_GNU_UNIQUE; break; diff --git a/bfd/elfcode.h b/bfd/elfcode.h index cc55c86..dd3896d 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -1292,6 +1292,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic) case STB_WEAK: sym->symbol.flags |= BSF_WEAK; break; + case STB_SECONDARY: + sym->symbol.flags |= BSF_SECONDARY; + break; case STB_GNU_UNIQUE: sym->symbol.flags |= BSF_GNU_UNIQUE; break; diff --git a/bfd/elflink.c b/bfd/elflink.c index d9e1abe..d6f8d9d 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -924,7 +924,7 @@ _bfd_elf_merge_symbol (bfd *abfd, int bind; bfd *oldbfd; bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon; - bfd_boolean newweak, oldweak, newfunc, oldfunc; + bfd_boolean newweak, oldweak, newfunc, oldfunc, weakbind, oldsecondary; const struct elf_backend_data *bed; *skip = FALSE; @@ -1007,8 +1007,13 @@ _bfd_elf_merge_symbol (bfd *abfd, break; } + oldsecondary = h->root.secondary != 0; + + /* Treat secondary symbols as weak symbols. */ + weakbind = bind == STB_WEAK || bind == STB_SECONDARY; + /* Differentiate strong and weak symbols. */ - newweak = bind == STB_WEAK; + newweak = weakbind; oldweak = (h->root.type == bfd_link_hash_defweak || h->root.type == bfd_link_hash_undefweak); @@ -1146,10 +1151,10 @@ _bfd_elf_merge_symbol (bfd *abfd, if it is weak. Otherwise, we clear it. */ if (!h->ref_dynamic) { - if (bind == STB_WEAK) + if (weakbind) h->dynamic_weak = 1; } - else if (bind != STB_WEAK) + else if (!weakbind) h->dynamic_weak = 0; } } @@ -1385,10 +1390,14 @@ _bfd_elf_merge_symbol (bfd *abfd, represent variables; this can cause confusion in principle, but any such confusion would seem to indicate an erroneous program or shared library. We also permit a common symbol in a regular - object to override a weak symbol in a shared object. */ + object to override a weak symbol in a shared object. + + We let a definition in a dynamic object override the old secondary + symbol. */ if (newdyn && newdef + && !oldsecondary && (olddef || (h->root.type == bfd_link_hash_common && (newweak || newfunc)))) @@ -1427,8 +1436,9 @@ _bfd_elf_merge_symbol (bfd *abfd, *size_change_ok = TRUE; } - /* Skip weak definitions of symbols that are already defined. */ - if (newdef && olddef && newweak) + /* Skip weak definitions of symbols that are already defined unless + the old definition is secondary. */ + if (newdef && olddef && newweak && !oldsecondary) { /* Don't skip new non-IR weak syms. */ if (!(oldbfd != NULL @@ -1456,18 +1466,20 @@ _bfd_elf_merge_symbol (bfd *abfd, always take precedence over symbols from dynamic objects, even if they are defined after the dynamic object in the link. + The new non-secondary definition overrides the old secondary + definition. + As above, we again permit a common symbol in a regular object to override a definition in a shared object if the shared object symbol is a function or is weak. */ flip = NULL; - if (!newdyn + if (((!newdyn && olddyn && h->def_dynamic) || oldsecondary) + && bind != STB_SECONDARY && (newdef || (bfd_is_com_section (sec) && (oldweak || oldfunc))) - && olddyn - && olddef - && h->def_dynamic) + && olddef) { /* Change the hash table entry to undefined, and let _bfd_generic_link_add_one_symbol do the right thing with the @@ -3847,6 +3859,7 @@ error_free_dyn: unsigned int old_alignment; bfd *old_bfd; bfd * undef_bfd = NULL; + unsigned int secondary; override = FALSE; @@ -3875,6 +3888,10 @@ error_free_dyn: flags = BSF_WEAK; break; + case STB_SECONDARY: + flags = BSF_SECONDARY; + break; + case STB_GNU_UNIQUE: flags = BSF_GNU_UNIQUE; break; @@ -4162,7 +4179,12 @@ error_free_dyn: && vernum > 1 && definition) h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1]; + + /* Remember if the old definition is secondary. */ + secondary = h->root.secondary; } + else + secondary = 0; if (! (_bfd_generic_link_add_one_symbol (info, abfd, name, flags, sec, value, NULL, FALSE, bed->collect, @@ -4346,10 +4368,14 @@ error_free_dyn: if (! definition) { h->ref_regular = 1; - if (bind != STB_WEAK) + /* Treat secondary symbols as weak symbols. */ + if (bind != STB_WEAK && bind != STB_SECONDARY) h->ref_regular_nonweak = 1; } - else + /* Mark it defined in a regular object if it is a + non-secondary definition or it hasn't been defined + in a dynamic object. */ + else if (!h->def_dynamic || bind != STB_SECONDARY) { h->def_regular = 1; if (h->def_dynamic) @@ -4371,6 +4397,10 @@ error_free_dyn: { h->def_dynamic = 1; h->dynamic_def = 1; + /* Dynamic definition overrides regular secondary + definition. */ + if (secondary) + h->def_regular = 0; } if (h->def_regular || h->ref_regular @@ -5064,7 +5094,9 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) if (! elf_link_is_defined_archive_symbol (abfd, symdef)) continue; } - else if (h->root.type != bfd_link_hash_undefined) + /* Keep searching if a definition is secondary. */ + else if (h->root.type != bfd_link_hash_undefined + && !h->root.secondary) { if (h->root.type != bfd_link_hash_undefweak) defined[i] = TRUE; @@ -8742,7 +8774,21 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) sym.st_info = ELF_ST_INFO (STB_GNU_UNIQUE, h->type); else if (h->root.type == bfd_link_hash_undefweak || h->root.type == bfd_link_hash_defweak) - sym.st_info = ELF_ST_INFO (STB_WEAK, h->type); + { + /* Generate defined secondary symbols for "ld -shared -z secondary" + and "ld -r". For undefined secondary symbols, we convert them + to weak symbols. We also convert defined secondary symbols in + executables to weak symbols since their bindings in executables + are final and can't be changed. */ + if ((flinfo->info->relocatable + || (!flinfo->info->executable + && flinfo->info->emit_secondary)) + && h->root.type == bfd_link_hash_defweak + && h->root.secondary) + sym.st_info = ELF_ST_INFO (STB_SECONDARY, h->type); + else + sym.st_info = ELF_ST_INFO (STB_WEAK, h->type); + } else sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type); sym.st_target_internal = h->target_internal; @@ -8873,7 +8919,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) if (sym.st_shndx == SHN_UNDEF && h->ref_regular && (ELF_ST_BIND (sym.st_info) == STB_GLOBAL - || ELF_ST_BIND (sym.st_info) == STB_WEAK)) + || ELF_ST_BIND (sym.st_info) == STB_WEAK + || ELF_ST_BIND (sym.st_info) == STB_SECONDARY)) { int bindtype; unsigned int type = ELF_ST_TYPE (sym.st_info); @@ -8899,10 +8946,12 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) sym.st_size = 0; /* If a non-weak symbol with non-default visibility is not defined - locally, it is a fatal error. */ + locally, it is a fatal error. Treat secondary symbols as weak + symbols. */ if (!flinfo->info->relocatable && ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT && ELF_ST_BIND (sym.st_info) != STB_WEAK + && ELF_ST_BIND (sym.st_info) != STB_SECONDARY && h->root.type == bfd_link_hash_undefined && !h->def_regular) { diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c index 6728371..91870c5 100644 --- a/bfd/elfn32-mips.c +++ b/bfd/elfn32-mips.c @@ -3153,7 +3153,10 @@ mips_elf_sym_is_global (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym) if (SGI_COMPAT (abfd)) return (sym->flags & BSF_SECTION_SYM) == 0; else - return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0 + return ((sym->flags & (BSF_GLOBAL + | BSF_WEAK + | BSF_SECONDARY + | BSF_GNU_UNIQUE)) != 0 || bfd_is_und_section (bfd_get_section (sym)) || bfd_is_com_section (bfd_get_section (sym))); } diff --git a/bfd/linker.c b/bfd/linker.c index 3caec96..182cfdf 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -1577,6 +1577,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, enum link_row row; struct bfd_link_hash_entry *h; bfd_boolean cycle; + unsigned int secondary; BFD_ASSERT (section != NULL); @@ -1626,15 +1627,53 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, return FALSE; } + /* Since secondary symbols have lower precedence than weak symbols, + we treat them as weak symbols here. */ + secondary = (flags & BSF_SECONDARY) != 0; + if (secondary) + switch (row) + { + default: + break; + + case UNDEF_ROW: + row = UNDEFW_ROW; + break; + + case DEF_ROW: + row = DEFW_ROW; + break; + } + if (hashp != NULL) *hashp = h; do { enum link_action action; + enum bfd_link_hash_type type; + + type = h->type; + /* Convert a secondary symbol to a weak symbol. Backend is + responsible to let a weak symbol override a secondary + symbol. */ + if (h->secondary) + switch (type) + { + default: + break; + + case bfd_link_hash_undefined: + type = bfd_link_hash_undefweak; + break; + + case bfd_link_hash_defined: + type = bfd_link_hash_defweak; + break; + } cycle = FALSE; - action = link_action[(int) row][(int) h->type]; + action = link_action[(int) row][(int) type]; switch (action) { case FAIL: @@ -1679,6 +1718,9 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, h->u.def.section = section; h->u.def.value = value; + /* Mark if this is a secondary symbol. */ + h->secondary = secondary; + /* If we have been asked to, we act like collect2 and identify all functions that might be global constructors and destructors and pass them up in a diff --git a/bfd/syms.c b/bfd/syms.c index bf5a488..69ced86 100644 --- a/bfd/syms.c +++ b/bfd/syms.c @@ -308,6 +308,10 @@ CODE_FRAGMENT . with this name and type in use. BSF_OBJECT must also be set. *} .#define BSF_GNU_UNIQUE (1 << 23) . +. {* A secondary global symbol, overridable without warnings by +. a regular or weak global symbol of the same name. *} +.#define BSF_SECONDARY (1 << 24) +. . flagword flags; . . {* A pointer to the section to which this symbol is @@ -491,6 +495,7 @@ bfd_print_symbol_vandf (bfd *abfd, void *arg, asymbol *symbol) ((type & BSF_LOCAL) ? (type & BSF_GLOBAL) ? '!' : 'l' : (type & BSF_GLOBAL) ? 'g' + : (type & BSF_SECONDARY) ? 's' : (type & BSF_GNU_UNIQUE) ? 'u' : ' '), (type & BSF_WEAK) ? 'w' : ' ', (type & BSF_CONSTRUCTOR) ? 'C' : ' ', @@ -694,6 +699,15 @@ bfd_decode_symclass (asymbol *symbol) } if (symbol->flags & BSF_GNU_UNIQUE) return 'u'; + if (symbol->flags & BSF_SECONDARY) + { + /* If secondary, determine if it's specifically an object + or non-object weak. */ + if (symbol->flags & BSF_OBJECT) + return 'Y'; + else + return 'S'; + } if (!(symbol->flags & (BSF_GLOBAL | BSF_LOCAL))) return '?'; diff --git a/binutils/nm.c b/binutils/nm.c index ad38e27..31e1508 100644 --- a/binutils/nm.c +++ b/binutils/nm.c @@ -438,6 +438,7 @@ filter_symbols (bfd *abfd, bfd_boolean is_dynamic, void *minisyms, /* PR binutls/12753: Unique symbols are global too. */ keep = ((sym->flags & (BSF_GLOBAL | BSF_WEAK + | BSF_SECONDARY | BSF_GNU_UNIQUE)) != 0 || bfd_is_und_section (sym->section) || bfd_is_com_section (sym->section)); diff --git a/binutils/readelf.c b/binutils/readelf.c index b1bacfd..9329344 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -8702,6 +8702,7 @@ get_symbol_binding (unsigned int binding) case STB_LOCAL: return "LOCAL"; case STB_GLOBAL: return "GLOBAL"; case STB_WEAK: return "WEAK"; + case STB_SECONDARY: return "SECOND"; default: if (binding >= STB_LOPROC && binding <= STB_HIPROC) snprintf (buff, sizeof (buff), _(": %d"), diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c index d7c7665..fc702cb 100644 --- a/gas/config/obj-elf.c +++ b/gas/config/obj-elf.c @@ -66,6 +66,7 @@ static void obj_elf_line (int); static void obj_elf_size (int); static void obj_elf_type (int); static void obj_elf_ident (int); +static void obj_elf_secondary (int); static void obj_elf_weak (int); static void obj_elf_local (int); static void obj_elf_visibility (int); @@ -94,6 +95,7 @@ static const pseudo_typeS elf_pseudo_table[] = {"type", obj_elf_type, 0}, {"version", obj_elf_version, 0}, {"weak", obj_elf_weak, 0}, + {"secondary", obj_elf_secondary, 0}, /* These define symbol visibility. */ {"internal", obj_elf_visibility, STV_INTERNAL}, @@ -437,6 +439,29 @@ obj_elf_local (int ignore ATTRIBUTE_UNUSED) } static void +obj_elf_secondary (int ignore ATTRIBUTE_UNUSED) +{ + int c; + symbolS *symbolP; + + do + { + symbolP = get_sym_from_input_line_and_check (); + c = *input_line_pointer; + S_SET_SECONDARY (symbolP); + if (c == ',') + { + input_line_pointer++; + SKIP_WHITESPACE (); + if (*input_line_pointer == '\n') + c = '\n'; + } + } + while (c == ','); + demand_empty_rest_of_line (); +} + +static void obj_elf_weak (int ignore ATTRIBUTE_UNUSED) { int c; @@ -1988,18 +2013,24 @@ elf_frob_symbol (symbolS *symp, int *puntp) if (S_IS_WEAK (symp)) S_SET_WEAK (symp2); + if (S_IS_SECONDARY (symp)) + S_SET_SECONDARY (symp2); + if (S_IS_EXTERNAL (symp)) S_SET_EXTERNAL (symp2); } } } - /* Double check weak symbols. */ - if (S_IS_WEAK (symp)) + /* Double check weak and secondary symbols. */ + if (S_IS_COMMON (symp)) { - if (S_IS_COMMON (symp)) + if (S_IS_WEAK (symp)) as_bad (_("symbol `%s' can not be both weak and common"), S_GET_NAME (symp)); + else if (S_IS_SECONDARY (symp)) + as_bad (_("symbol `%s' can not be both secondary and common"), + S_GET_NAME (symp)); } #ifdef TC_MIPS @@ -2214,7 +2245,7 @@ elf_frob_file_before_adjust (void) /* If there was .weak foo, but foo was neither defined nor used anywhere, remove it. */ - else if (S_IS_WEAK (symp) + else if ((S_IS_WEAK (symp) || S_IS_SECONDARY (symp)) && symbol_used_p (symp) == 0 && symbol_used_in_reloc_p (symp) == 0) symbol_remove (symp, &symbol_rootP, &symbol_lastP); diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index 5b5d268..d587857 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -4071,6 +4071,7 @@ Some machine configurations provide additional directives. * Print:: @code{.print @var{string}} @ifset ELF * Protected:: @code{.protected @var{names}} +* Secondary:: @code{.secondary @var{names}} @end ifset * Psize:: @code{.psize @var{lines}, @var{columns}} @@ -5753,6 +5754,14 @@ their binding: local, global or weak). The directive sets the visibility to components that defines them must be resolved to the definition in that component, even if a definition in another component would normally preempt this. + +@node Secondary +@section @code{.secondary @var{names}} + +@cindex @code{secondary} directive +This directive sets the secondary attribute on the comma separated list +of symbol @code{names}. If the symbols do not already exist, they will +be created. @end ifset @node Psize diff --git a/gas/symbols.c b/gas/symbols.c index 1f325c4..79ea5bc 100644 --- a/gas/symbols.c +++ b/gas/symbols.c @@ -2035,6 +2035,14 @@ S_IS_WEAK (symbolS *s) } int +S_IS_SECONDARY (symbolS *s) +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + return (s->bsym->flags & BSF_SECONDARY) != 0; +} + +int S_IS_WEAKREFR (symbolS *s) { if (LOCAL_SYMBOL_CHECK (s)) @@ -2081,7 +2089,7 @@ S_FORCE_RELOC (symbolS *s, int strict) return ((struct local_symbol *) s)->lsy_section == undefined_section; return ((strict - && ((s->bsym->flags & BSF_WEAK) != 0 + && ((s->bsym->flags & (BSF_WEAK | BSF_SECONDARY)) != 0 || (EXTERN_FORCE_RELOC && (s->bsym->flags & BSF_GLOBAL) != 0))) || (s->bsym->flags & BSF_GNU_INDIRECT_FUNCTION) != 0 @@ -2217,9 +2225,9 @@ S_SET_EXTERNAL (symbolS *s) { if (LOCAL_SYMBOL_CHECK (s)) s = local_symbol_convert ((struct local_symbol *) s); - if ((s->bsym->flags & BSF_WEAK) != 0) + if ((s->bsym->flags & (BSF_WEAK | BSF_SECONDARY)) != 0) { - /* Let .weak override .global. */ + /* Let .weak/.secondary override .global. */ return; } if (s->bsym->flags & BSF_SECTION_SYM) @@ -2242,7 +2250,7 @@ S_SET_EXTERNAL (symbolS *s) } #endif s->bsym->flags |= BSF_GLOBAL; - s->bsym->flags &= ~(BSF_LOCAL | BSF_WEAK); + s->bsym->flags &= ~(BSF_LOCAL | BSF_WEAK | BSF_SECONDARY); #ifdef TE_PE if (! an_external_name && S_GET_NAME(s)[0] != '.') @@ -2255,13 +2263,13 @@ S_CLEAR_EXTERNAL (symbolS *s) { if (LOCAL_SYMBOL_CHECK (s)) return; - if ((s->bsym->flags & BSF_WEAK) != 0) + if ((s->bsym->flags & (BSF_WEAK | BSF_SECONDARY)) != 0) { - /* Let .weak override. */ + /* Let .weak/.secondary override. */ return; } s->bsym->flags |= BSF_LOCAL; - s->bsym->flags &= ~(BSF_GLOBAL | BSF_WEAK); + s->bsym->flags &= ~(BSF_GLOBAL | BSF_WEAK | BSF_SECONDARY); } void @@ -2273,7 +2281,16 @@ S_SET_WEAK (symbolS *s) obj_set_weak_hook (s); #endif s->bsym->flags |= BSF_WEAK; - s->bsym->flags &= ~(BSF_GLOBAL | BSF_LOCAL); + s->bsym->flags &= ~(BSF_GLOBAL | BSF_SECONDARY | BSF_LOCAL); +} + +void +S_SET_SECONDARY (symbolS *s) +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + s->bsym->flags |= BSF_SECONDARY; + s->bsym->flags &= ~(BSF_GLOBAL | BSF_WEAK | BSF_LOCAL); } void @@ -2330,6 +2347,12 @@ S_CLEAR_WEAKREFD (symbolS *s) s->bsym->flags &= ~BSF_WEAK; s->bsym->flags |= BSF_LOCAL; } + /* The same applies to secondary symbol. */ + else if (s->bsym->flags & BSF_SECONDARY) + { + s->bsym->flags &= ~BSF_SECONDARY; + s->bsym->flags |= BSF_LOCAL; + } } } diff --git a/gas/symbols.h b/gas/symbols.h index a3a31f7..6ec3266 100644 --- a/gas/symbols.h +++ b/gas/symbols.h @@ -92,6 +92,7 @@ extern void S_SET_VALUE (symbolS *, valueT); extern int S_IS_FUNCTION (symbolS *); extern int S_IS_EXTERNAL (symbolS *); extern int S_IS_WEAK (symbolS *); +extern int S_IS_SECONDARY (symbolS *); extern int S_IS_WEAKREFR (symbolS *); extern int S_IS_WEAKREFD (symbolS *); extern int S_IS_COMMON (symbolS *); @@ -110,6 +111,7 @@ extern void S_SET_EXTERNAL (symbolS *); extern void S_SET_NAME (symbolS *, const char *); extern void S_CLEAR_EXTERNAL (symbolS *); extern void S_SET_WEAK (symbolS *); +extern void S_SET_SECONDARY (symbolS *); extern void S_SET_WEAKREFR (symbolS *); extern void S_CLEAR_WEAKREFR (symbolS *); extern void S_SET_WEAKREFD (symbolS *); diff --git a/gas/testsuite/gas/elf/common3.d b/gas/testsuite/gas/elf/common3.d new file mode 100644 index 0000000..e73f6c5 --- /dev/null +++ b/gas/testsuite/gas/elf/common3.d @@ -0,0 +1,2 @@ +#name: secondary and common directives +#error-output: common3.l diff --git a/gas/testsuite/gas/elf/common3.l b/gas/testsuite/gas/elf/common3.l new file mode 100644 index 0000000..58d5142 --- /dev/null +++ b/gas/testsuite/gas/elf/common3.l @@ -0,0 +1,2 @@ +[^:]*: Assembler messages: +[^:]*: Error: symbol `foobar' can not be both secondary and common diff --git a/gas/testsuite/gas/elf/common3.s b/gas/testsuite/gas/elf/common3.s new file mode 100644 index 0000000..df8b7ed --- /dev/null +++ b/gas/testsuite/gas/elf/common3.s @@ -0,0 +1,2 @@ + .secondary foobar + .comm foobar,30 diff --git a/gas/testsuite/gas/elf/common4.d b/gas/testsuite/gas/elf/common4.d new file mode 100644 index 0000000..aca59c0 --- /dev/null +++ b/gas/testsuite/gas/elf/common4.d @@ -0,0 +1,2 @@ +#name: common and secondary directives +#error-output: common4.l diff --git a/gas/testsuite/gas/elf/common4.l b/gas/testsuite/gas/elf/common4.l new file mode 100644 index 0000000..58d5142 --- /dev/null +++ b/gas/testsuite/gas/elf/common4.l @@ -0,0 +1,2 @@ +[^:]*: Assembler messages: +[^:]*: Error: symbol `foobar' can not be both secondary and common diff --git a/gas/testsuite/gas/elf/common4.s b/gas/testsuite/gas/elf/common4.s new file mode 100644 index 0000000..37bd0ce --- /dev/null +++ b/gas/testsuite/gas/elf/common4.s @@ -0,0 +1,2 @@ + .comm foobar,30 + .secondary foobar diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp index 7897788..7c5095b 100644 --- a/gas/testsuite/gas/elf/elf.exp +++ b/gas/testsuite/gas/elf/elf.exp @@ -188,6 +188,8 @@ if { [is_elf_format] } then { run_dump_test "common1" run_dump_test "common2" + run_dump_test "common3" + run_dump_test "common4" load_lib gas-dg.exp dg-init diff --git a/gas/testsuite/gas/elf/type.e b/gas/testsuite/gas/elf/type.e index fbc9aac..2968fd0 100644 --- a/gas/testsuite/gas/elf/type.e +++ b/gas/testsuite/gas/elf/type.e @@ -3,5 +3,7 @@ +.: 0+0 +1 +OBJECT +LOCAL +DEFAULT +. object +.: 0+1 +1 +TLS +LOCAL +DEFAULT +. tls_object +..: 0+2 +1 +NOTYPE +LOCAL +DEFAULT +. notype + +.: 0+2 +1 +FUNC +SECOND +DEFAULT +. secondary_function +..: 0+3 +1 +OBJECT +UNIQUE +DEFAULT +. unique_global + +..: 0+4 +1 +OBJECT +SECOND +DEFAULT +. secondary_object +..: 0+1 +1 +(COMMON|OBJECT) +GLOBAL +DEFAULT +COM common diff --git a/gas/testsuite/gas/elf/type.s b/gas/testsuite/gas/elf/type.s index d0a1afd..bd7df2c 100644 --- a/gas/testsuite/gas/elf/type.s +++ b/gas/testsuite/gas/elf/type.s @@ -10,6 +10,12 @@ function: indirect_function: .byte 0x0 + .size secondary_function,1 + .secondary secondary_function + .type secondary_function,%function +secondary_function: + .byte 0x0 + .data .type object,%object @@ -32,6 +38,11 @@ unique_global: .byte 0x0 .size unique_global,1 + .type secondary_object,%object + .secondary secondary_object +secondary_object: + .byte 0x0 + .size secondary_object,1 + .comm common, 1 .type common,STT_COMMON - \ No newline at end of file diff --git a/include/bfdlink.h b/include/bfdlink.h index d900b47..2a116c9 100644 --- a/include/bfdlink.h +++ b/include/bfdlink.h @@ -95,6 +95,9 @@ struct bfd_link_hash_entry unsigned int non_ir_ref : 1; + /* Set if it is a secondary symbol. */ + unsigned int secondary : 1; + /* A union of information depending upon the type. */ union { @@ -346,6 +349,9 @@ struct bfd_link_info /* TRUE if .gnu.hash section should be created. */ unsigned int emit_gnu_hash: 1; + /* TRUE if secondary symbols should be generated. */ + unsigned int emit_secondary: 1; + /* If TRUE reduce memory overheads, at the expense of speed. This will cause map file generation to use an O(N^2) algorithm and disable caching ELF symbol buffer. */ diff --git a/include/elf/common.h b/include/elf/common.h index 58e489a..2a4452b 100644 --- a/include/elf/common.h +++ b/include/elf/common.h @@ -649,6 +649,7 @@ #define STB_LOCAL 0 /* Symbol not visible outside obj */ #define STB_GLOBAL 1 /* Symbol visible outside obj */ #define STB_WEAK 2 /* Like globals, lower precedence */ +#define STB_SECONDARY 3 /* Like weaks, lower precedence */ #define STB_LOOS 10 /* OS-specific semantics */ #define STB_GNU_UNIQUE 10 /* Symbol is unique in namespace */ #define STB_HIOS 12 /* OS-specific semantics */ diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index 2b7a352..18f0010 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -2334,6 +2334,8 @@ fragment < + +void +bar (void) +{ +#ifdef SHARED + printf ("library bar (SHARED)\n"); +#else + printf ("library bar\n"); +#endif +} diff --git a/ld/testsuite/ld-elf/library1.out b/ld/testsuite/ld-elf/library1.out new file mode 100644 index 0000000..2050e74 --- /dev/null +++ b/ld/testsuite/ld-elf/library1.out @@ -0,0 +1 @@ +library bar diff --git a/ld/testsuite/ld-elf/library2.c b/ld/testsuite/ld-elf/library2.c new file mode 100644 index 0000000..271ebd6 --- /dev/null +++ b/ld/testsuite/ld-elf/library2.c @@ -0,0 +1,12 @@ +#include + +void +__attribute__((weak)) +bar (void) +{ +#ifdef SHARED + printf ("weak library bar (SHARED)\n"); +#else + printf ("weak library bar\n"); +#endif +} diff --git a/ld/testsuite/ld-elf/library2.out b/ld/testsuite/ld-elf/library2.out new file mode 100644 index 0000000..ddd3d10 --- /dev/null +++ b/ld/testsuite/ld-elf/library2.out @@ -0,0 +1 @@ +weak library bar diff --git a/ld/testsuite/ld-elf/library3.out b/ld/testsuite/ld-elf/library3.out new file mode 100644 index 0000000..881856e --- /dev/null +++ b/ld/testsuite/ld-elf/library3.out @@ -0,0 +1 @@ +library bar (SHARED) diff --git a/ld/testsuite/ld-elf/library4.out b/ld/testsuite/ld-elf/library4.out new file mode 100644 index 0000000..1ff1840 --- /dev/null +++ b/ld/testsuite/ld-elf/library4.out @@ -0,0 +1 @@ +weak library bar (SHARED) diff --git a/ld/testsuite/ld-elf/secondary-main.c b/ld/testsuite/ld-elf/secondary-main.c new file mode 100644 index 0000000..8d509ad --- /dev/null +++ b/ld/testsuite/ld-elf/secondary-main.c @@ -0,0 +1,8 @@ +extern void bar (void); + +int +main (void) +{ + bar (); + return 0; +} diff --git a/ld/testsuite/ld-elf/secondary.c b/ld/testsuite/ld-elf/secondary.c new file mode 100644 index 0000000..6d64ed7 --- /dev/null +++ b/ld/testsuite/ld-elf/secondary.c @@ -0,0 +1,9 @@ +#include + +asm (".secondary bar"); + +void +bar (void) +{ + printf ("secondary bar\n"); +} diff --git a/ld/testsuite/ld-elf/secondary.exp b/ld/testsuite/ld-elf/secondary.exp new file mode 100644 index 0000000..434b99e --- /dev/null +++ b/ld/testsuite/ld-elf/secondary.exp @@ -0,0 +1,94 @@ +# Expect script for ELF secondary symbol tests. +# Copyright 2012 +# Free Software Foundation, Inc. +# +# This file is part of the GNU Binutils. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. +# + +# Exclude non-ELF targets. + +# The following tests require running the executable generated by ld, +# or enough of a build environment to create a fully linked executable. +# This is not commonly available when testing a cross-built linker. +if ![isnative] { + return +} + +if ![is_elf_format] { + return +} + +# Check to see if the C compiler works +if { [which $CC] == 0 } { + return +} + +set build_tests { + {"Build secondary.so" + "-shared" "-fPIC" + {secondary.c} {} "secondary.so"} + {"Build library1.so" + "-shared" "-fPIC -DSHARED" + {library1.c} {} "library1.so"} + {"Build library2.so" + "-shared" "-fPIC -DSHARED" + {library2.c} {} "library2.so"} + {"Build library1.a" + "" "" + {library1.c} {} "library1.a"} + {"Build library2.a" + "" "" + {library2.c} {} "library2.a"} +} + +run_cc_link_tests $build_tests + +set run_tests { + {"Run secondary-main with secondary.o" + "tmpdir/secondary.o" "" + {secondary-main.c} "secondary1" "secondary1.out"} + {"Run secondary-main with secondary.so" + "tmpdir/secondary.so" "" + {secondary-main.c} "secondary2" "secondary1.out"} + {"Run secondary-main with secondary.o library1.o" + "tmpdir/secondary.o tmpdir/secondary.o tmpdir/library1.o" "" + {secondary-main.c} "secondary3" "library1.out"} + {"Run secondary-main with library1.o secondary.o" + "tmpdir/library1.o tmpdir/secondary.o tmpdir/secondary.o" "" + {secondary-main.c} "secondary4" "library1.out"} + {"Run secondary-main with secondary.o library2.o" + "tmpdir/secondary.o tmpdir/library2.o" "" + {secondary-main.c} "secondary5" "library2.out"} + {"Run secondary-main with library2.o secondary.o" + "tmpdir/library2.o tmpdir/secondary.o" "" + {secondary-main.c} "secondary6" "library2.out"} + {"Run secondary-main with secondary.o library1.so" + "tmpdir/secondary.o tmpdir/library1.so" "" + {secondary-main.c} "secondary7" "library3.out"} + {"Run secondary-main with library1.so secondary.o" + "tmpdir/library1.so tmpdir/secondary.o" "" + {secondary-main.c} "secondary8" "library3.out"} + {"Run secondary-main with secondary.o library2.so" + "tmpdir/secondary.o tmpdir/library2.so" "" + {secondary-main.c} "secondary9" "library4.out"} + {"Run secondary-main with library2.so secondary.o" + "tmpdir/library2.so tmpdir/secondary.o" "" + {secondary-main.c} "secondary10" "library4.out"} +} + +run_ld_link_exec_tests [] $run_tests diff --git a/ld/testsuite/ld-elf/secondary1.out b/ld/testsuite/ld-elf/secondary1.out new file mode 100644 index 0000000..8d9378f --- /dev/null +++ b/ld/testsuite/ld-elf/secondary1.out @@ -0,0 +1 @@ +secondary bar