aboutsummaryrefslogtreecommitdiff
path: root/patches/binutils-secondary.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/binutils-secondary.patch')
-rw-r--r--patches/binutils-secondary.patch2197
1 files changed, 2197 insertions, 0 deletions
diff --git a/patches/binutils-secondary.patch b/patches/binutils-secondary.patch
new file mode 100644
index 0000000..eeeb95e
--- /dev/null
+++ b/patches/binutils-secondary.patch
@@ -0,0 +1,2197 @@
+From c7beb33d82923479aab9638145e23b26f4c68e2d Mon Sep 17 00:00:00 2001
+From: "H.J. Lu" <hjl.tools@gmail.com>
+Date: Mon, 4 Nov 2013 09:35:07 -0800
+Subject: [PATCH] Add STB_SECONDARY support to gas and ld
+
+STB_SECONDARY is similar to STB_WEAK. But a STB_SECONDARY definition
+can be overridden by STB_GLOBAL or STB_WEAK definition at link-time
+as well as run-time. Linker also search archive library and extract
+archive members to resolve defined and undefined STB_SECONDARY symbol.
+---
+ ChangeLog.secondary | 221 +++++++++++++++++++++++++++++++++++
+ bfd/archive.c | 1 +
+ bfd/bfd-in2.h | 4 +
+ bfd/elf.c | 10 +-
+ bfd/elf32-mips.c | 5 +-
+ bfd/elf64-ia64-vms.c | 4 +
+ bfd/elfcode.h | 3 +
+ bfd/elflink.c | 171 ++++++++++++++++++++-------
+ bfd/elfn32-mips.c | 5 +-
+ bfd/linker.c | 44 ++++++-
+ bfd/syms.c | 14 +++
+ binutils/nm.c | 1 +
+ binutils/readelf.c | 1 +
+ gas/config/obj-elf.c | 42 ++++++-
+ gas/doc/as.texinfo | 9 ++
+ gas/symbols.c | 39 +++++--
+ gas/symbols.h | 2 +
+ gas/testsuite/gas/elf/common3.d | 2 +
+ gas/testsuite/gas/elf/common3.l | 2 +
+ gas/testsuite/gas/elf/common3.s | 2 +
+ gas/testsuite/gas/elf/common4.d | 2 +
+ gas/testsuite/gas/elf/common4.l | 2 +
+ gas/testsuite/gas/elf/common4.s | 2 +
+ gas/testsuite/gas/elf/elf.exp | 5 +
+ gas/testsuite/gas/elf/secondary1.e | 4 +
+ gas/testsuite/gas/elf/secondary1.s | 33 ++++++
+ gas/testsuite/gas/elf/secondary2.e | 1 +
+ gas/testsuite/gas/elf/secondary2.s | 5 +
+ gas/testsuite/gas/elf/type.e | 2 +
+ gas/testsuite/gas/elf/type.s | 13 ++-
+ include/bfdlink.h | 6 +
+ include/elf/common.h | 1 +
+ ld/emultempl/elf32.em | 4 +
+ ld/ld.texinfo | 4 +
+ ld/ldmain.c | 1 +
+ ld/testsuite/ld-elf/library1.c | 11 ++
+ ld/testsuite/ld-elf/library1.out | 1 +
+ ld/testsuite/ld-elf/library2.c | 12 ++
+ ld/testsuite/ld-elf/library2.out | 1 +
+ ld/testsuite/ld-elf/library3.out | 1 +
+ ld/testsuite/ld-elf/library4.out | 1 +
+ ld/testsuite/ld-elf/library5a.c | 16 +++
+ ld/testsuite/ld-elf/library5b.c | 10 ++
+ ld/testsuite/ld-elf/library6a.c | 4 +
+ ld/testsuite/ld-elf/library6b.c | 7 ++
+ ld/testsuite/ld-elf/library6c.c | 9 ++
+ ld/testsuite/ld-elf/library7a.c | 1 +
+ ld/testsuite/ld-elf/library7b.c | 7 ++
+ ld/testsuite/ld-elf/library7c.c | 3 +
+ ld/testsuite/ld-elf/library8.map | 4 +
+ ld/testsuite/ld-elf/library8a.c | 10 ++
+ ld/testsuite/ld-elf/library8a.rd | 5 +
+ ld/testsuite/ld-elf/library8b.c | 4 +
+ ld/testsuite/ld-elf/library8b.rd | 5 +
+ ld/testsuite/ld-elf/library8c.c | 7 ++
+ ld/testsuite/ld-elf/library8c.rd | 5 +
+ ld/testsuite/ld-elf/secondary-foo.c | 7 ++
+ ld/testsuite/ld-elf/secondary-main.c | 8 ++
+ ld/testsuite/ld-elf/secondary.c | 9 ++
+ ld/testsuite/ld-elf/secondary.exp | 176 ++++++++++++++++++++++++++++
+ ld/testsuite/ld-elf/secondary.rd | 5 +
+ ld/testsuite/ld-elf/secondary1.out | 1 +
+ ld/testsuite/ld-elf/secondary1.rd | 5 +
+ ld/testsuite/ld-elf/secondary2.rd | 5 +
+ ld/testsuite/ld-elf/secondary3.rd | 5 +
+ ld/testsuite/ld-elf/secondary3a.s | 4 +
+ ld/testsuite/ld-elf/secondary3b.s | 20 ++++
+ ld/testsuite/ld-elf/secondary4.rd | 5 +
+ ld/testsuite/ld-elf/secondary4.s | 9 ++
+ ld/testsuite/ld-elf/secondary5.c | 10 ++
+ ld/testsuite/ld-elf/secondary5.out | 3 +
+ ld/testsuite/ld-elf/secondary6.c | 11 ++
+ ld/testsuite/ld-elf/secondary6.out | 1 +
+ ld/testsuite/ld-elf/secondary7.c | 13 +++
+ ld/testsuite/ld-elf/secondary7.out | 1 +
+ 75 files changed, 1026 insertions(+), 63 deletions(-)
+ create mode 100644 ChangeLog.secondary
+ create mode 100644 gas/testsuite/gas/elf/common3.d
+ create mode 100644 gas/testsuite/gas/elf/common3.l
+ create mode 100644 gas/testsuite/gas/elf/common3.s
+ create mode 100644 gas/testsuite/gas/elf/common4.d
+ create mode 100644 gas/testsuite/gas/elf/common4.l
+ create mode 100644 gas/testsuite/gas/elf/common4.s
+ create mode 100644 gas/testsuite/gas/elf/secondary1.e
+ create mode 100644 gas/testsuite/gas/elf/secondary1.s
+ create mode 100644 gas/testsuite/gas/elf/secondary2.e
+ create mode 100644 gas/testsuite/gas/elf/secondary2.s
+ create mode 100644 ld/testsuite/ld-elf/library1.c
+ create mode 100644 ld/testsuite/ld-elf/library1.out
+ create mode 100644 ld/testsuite/ld-elf/library2.c
+ create mode 100644 ld/testsuite/ld-elf/library2.out
+ create mode 100644 ld/testsuite/ld-elf/library3.out
+ create mode 100644 ld/testsuite/ld-elf/library4.out
+ create mode 100644 ld/testsuite/ld-elf/library5a.c
+ create mode 100644 ld/testsuite/ld-elf/library5b.c
+ create mode 100644 ld/testsuite/ld-elf/library6a.c
+ create mode 100644 ld/testsuite/ld-elf/library6b.c
+ create mode 100644 ld/testsuite/ld-elf/library6c.c
+ create mode 100644 ld/testsuite/ld-elf/library7a.c
+ create mode 100644 ld/testsuite/ld-elf/library7b.c
+ create mode 100644 ld/testsuite/ld-elf/library7c.c
+ create mode 100644 ld/testsuite/ld-elf/library8.map
+ create mode 100644 ld/testsuite/ld-elf/library8a.c
+ create mode 100644 ld/testsuite/ld-elf/library8a.rd
+ create mode 100644 ld/testsuite/ld-elf/library8b.c
+ create mode 100644 ld/testsuite/ld-elf/library8b.rd
+ create mode 100644 ld/testsuite/ld-elf/library8c.c
+ create mode 100644 ld/testsuite/ld-elf/library8c.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary-foo.c
+ create mode 100644 ld/testsuite/ld-elf/secondary-main.c
+ create mode 100644 ld/testsuite/ld-elf/secondary.c
+ create mode 100644 ld/testsuite/ld-elf/secondary.exp
+ create mode 100644 ld/testsuite/ld-elf/secondary.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary1.out
+ create mode 100644 ld/testsuite/ld-elf/secondary1.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary2.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary3.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary3a.s
+ create mode 100644 ld/testsuite/ld-elf/secondary3b.s
+ create mode 100644 ld/testsuite/ld-elf/secondary4.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary4.s
+ create mode 100644 ld/testsuite/ld-elf/secondary5.c
+ create mode 100644 ld/testsuite/ld-elf/secondary5.out
+ create mode 100644 ld/testsuite/ld-elf/secondary6.c
+ create mode 100644 ld/testsuite/ld-elf/secondary6.out
+ create mode 100644 ld/testsuite/ld-elf/secondary7.c
+ create mode 100644 ld/testsuite/ld-elf/secondary7.out
+
+diff --git a/ChangeLog.secondary b/ChangeLog.secondary
+new file mode 100644
+index 0000000..f3bb59d
+--- /dev/null
++++ b/ChangeLog.secondary
+@@ -0,0 +1,221 @@
++bfd/
++
++2012-09-11 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elf-bfd.h (_bfd_elf_merge_symbol): Add a boolean argument to
++ indicate if the old definition is secondary.
++
++ * elf32-sh-symbian.c (sh_symbian_relocate_section): Pass FALSE
++ to _bfd_elf_merge_symbol.
++
++ * elflink.c (_bfd_elf_merge_symbol): Add a boolean argument to
++ indicate if the old definition is secondary. Set OLDSECONADRY if
++ it isn't TRUE. Treat old secondary symbol as weak.
++ (_bfd_elf_add_default_symbol): Add a boolean argument to if the
++ old definition is secondary.
++ (elf_link_add_object_symbols): Pass oldsecondary to
++ _bfd_elf_merge_symbol and _bfd_elf_add_default_symbol.
++
++2012-09-06 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elflink.c (is_global_data_symbol_definition): Renamed to ...
++ (is_global_symbol_definition): This. If secondary symbols are
++ ignored, count function and common symbols as global definition.
++ (elf_link_is_defined_archive_symbol): Updated.
++
++2012-09-06 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elflink.c (is_global_data_symbol_definition): Add an argument
++ to ignore secondary symbols.
++ (elf_link_is_defined_archive_symbol): Likewise and pass it to
++ is_global_data_symbol_definition.
++ (elf_link_add_archive_symbols): Ignore another secondary
++ definition.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elflink.c (elf_link_output_extsym): Generate STB_SECONDARY
++ symbols if needed.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elf.c (swap_out_syms): Output undefined secondary symbols
++ as weak.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * 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): Treat 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 <hongjiu.lu@intel.com>
++
++ * 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 <hongjiu.lu@intel.com>
++
++ * nm.c (filter_symbols): Treat BSF_SECONDARY symbol as global.
++
++ * readelf.c (get_symbol_binding): Handle STB_SECONDARY.
++
++gas/
++
++2012-09-05 H.J. Lu <hongjiu.lu@intel.com>
++
++ * config/obj-elf.c (obj_elf_weak): Don't set symbol weak on
++ secondary symbol.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * config/obj-elf.c (elf_frob_symbol): Handle secondary symbol
++ for .symver. Also remove the unused secondary symbol.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * 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): Also check secondary symbols.
++
++ * doc/as.texinfo: Document .secondary directive.
++
++gas/testsuite/
++
++2012-09-05 H.J. Lu <hongjiu.lu@intel.com>
++
++ * 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/secondary1.e: Likewise.
++ * gas/elf/secondary1.s: Likewise.
++ * gas/elf/secondary2.e: Likewise.
++ * gas/elf/secondary2.s: Likewise.
++
++ * gas/elf/elf.exp: Run common3, common4, secondary1 and
++ secondary2.
++
++ * gas/elf/type.s: Add .secondary tests.
++ * gas/elf/type.e: Updated.
++
++include/
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * bfdlink.h (bfd_link_info): Add emit_secondary.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * bfdlink.h (bfd_link_hash_entry): Add secondary.
++
++include/elf/
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * common.h (STB_SECONDARY): New.
++
++ld/
++
++2012-09-08 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ld.texinfo: Change "-z secondary" to "-z nosecondary".
++
++ * ldmain.c (main): Initialize link_info.emit_secondary to TRUE.
++
++ * emultempl/elf32.em (gld${EMULATION_NAME}_handle_option): Set
++ to link_info.emit_secondary to FALSE for "-z nosecondary".
++ (gld${EMULATION_NAME}_list_options): Replace "-z secondary" with
++ "-z nosecondary".
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * 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-09-08 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ld-elf/secondary.exp: Update -Wl,-z,secondary with
++ -Wl,-z,nosecondary.
++
++2012-09-06 H.J. Lu <hongjiu.lu@intel.com>
++
++ * 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/library5a.c: Likewise.
++ * ld-elf/library5b.c: Likewise.
++ * ld-elf/library6a.c: Likewise.
++ * ld-elf/library6b.c: Likewise.
++ * ld-elf/library6c.c: Likewise.
++ * ld-elf/library7a.c: Likewise.
++ * ld-elf/library7b.c: Likewise.
++ * ld-elf/library7c.c: Likewise.
++ * ld-elf/secondary-foo.c: Likewise.
++ * ld-elf/secondary-main.c: Likewise.
++ * ld-elf/secondary.c: Likewise.
++ * ld-elf/secondary.exp: Likewise.
++ * ld-elf/secondary.rd: Likewise.
++ * ld-elf/secondary1.out: Likewise.
++ * ld-elf/secondary1.rd: Likewise.
++ * ld-elf/secondary2.rd: Likewise.
++ * ld-elf/secondary3.rd: Likewise.
++ * ld-elf/secondary3a.s: Likewise.
++ * ld-elf/secondary3b.s: Likewise.
++ * ld-elf/secondary4.rd: Likewise.
++ * ld-elf/secondary4.s: Likewise.
++ * ld-elf/secondary5.c: Likewise.
++ * ld-elf/secondary5.out: Likewise.
++ * ld-elf/secondary6.c: Likewise.
++ * ld-elf/secondary6.out: Likewise.
++ * ld-elf/secondary7.c: Likewise.
++ * ld-elf/secondary7.out: Likewise.
++ * ld-elf/library8.map: Likewise.
++ * ld-elf/library8a.c: Likewise.
++ * ld-elf/library8a.rd: Likewise.
++ * ld-elf/library8b.c: Likewise.
++ * ld-elf/library8b.rd: Likewise.
++ * ld-elf/library8c.c: Likewise.
++ * ld-elf/library8c.rd: Likewise.
+diff --git a/bfd/archive.c b/bfd/archive.c
+index 40a3395..0d80fc5 100644
+--- a/bfd/archive.c
++++ b/bfd/archive.c
+@@ -2337,6 +2337,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 27fc3fe..fdc1138 100644
+--- a/bfd/bfd-in2.h
++++ b/bfd/bfd-in2.h
+@@ -6168,6 +6168,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 9dc6b6d..97816f4 100644
+--- a/bfd/elf.c
++++ b/bfd/elf.c
+@@ -3259,7 +3259,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)));
+ }
+@@ -6922,8 +6925,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);
+@@ -6937,6 +6941,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 af405bc..e84efad 100644
+--- a/bfd/elf32-mips.c
++++ b/bfd/elf32-mips.c
+@@ -2154,7 +2154,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 dd86e3c..0ff1798 100644
+--- a/bfd/elf64-ia64-vms.c
++++ b/bfd/elf64-ia64-vms.c
+@@ -4926,6 +4926,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 a49a708..b09ab77 100644
+--- a/bfd/elfcode.h
++++ b/bfd/elfcode.h
+@@ -1281,6 +1281,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 c1e7948..984cee6 100644
+--- a/bfd/elflink.c
++++ b/bfd/elflink.c
+@@ -885,7 +885,8 @@ elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
+ overriding a new definition. We set TYPE_CHANGE_OK if it is OK for
+ the type to change. We set SIZE_CHANGE_OK if it is OK for the size
+ to change. By OK to change, we mean that we shouldn't warn if the
+- type or size does change. */
++ type or size does change. If OLDSECONARY is TRUE, the old definion
++ is a secondary symbol. */
+
+ static bfd_boolean
+ _bfd_elf_merge_symbol (bfd *abfd,
+@@ -895,6 +896,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ asection **psec,
+ bfd_vma *pvalue,
+ struct elf_link_hash_entry **sym_hash,
++ bfd_boolean oldsecondary,
+ bfd **poldbfd,
+ bfd_boolean *pold_weak,
+ unsigned int *pold_alignment,
+@@ -910,7 +912,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;
+ const struct elf_backend_data *bed;
+
+ *skip = FALSE;
+@@ -968,9 +970,17 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ if (poldbfd && *poldbfd == NULL)
+ *poldbfd = oldbfd;
+
++ /* Set OLDSECONADRY if it isn't TRUE. */
++ if (!oldsecondary)
++ 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;
+- oldweak = (h->root.type == bfd_link_hash_defweak
++ newweak = weakbind;
++ oldweak = (oldsecondary
++ || h->root.type == bfd_link_hash_defweak
+ || h->root.type == bfd_link_hash_undefweak);
+ if (pold_weak)
+ *pold_weak = oldweak;
+@@ -1001,7 +1011,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ {
+ if (bfd_is_und_section (sec))
+ {
+- if (bind != STB_WEAK)
++ if (!weakbind)
+ {
+ h->ref_dynamic_nonweak = 1;
+ hi->ref_dynamic_nonweak = 1;
+@@ -1250,7 +1260,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
+
+ if (newdef && !newdyn && olddyn)
+ newweak = FALSE;
+- if (olddef && newdyn)
++ if (olddef && newdyn && !oldsecondary)
+ oldweak = FALSE;
+
+ /* Allow changes between different types of function symbol. */
+@@ -1365,10 +1375,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))))
+@@ -1407,8 +1421,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
+@@ -1439,18 +1454,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
+@@ -1553,8 +1570,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
+
+ /* This function is called to create an indirect symbol from the
+ default for the symbol with the default version if needed. The
+- symbol is described by H, NAME, SYM, SEC, and VALUE. We
+- set DYNSYM if the new indirect symbol is dynamic. */
++ symbol is described by H, NAME, SYM, SEC, VALUE, and OLDSECONDARY.
++ We set DYNSYM if the new indirect symbol is dynamic. */
+
+ static bfd_boolean
+ _bfd_elf_add_default_symbol (bfd *abfd,
+@@ -1564,6 +1581,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
+ Elf_Internal_Sym *sym,
+ asection *sec,
+ bfd_vma value,
++ bfd_boolean oldsecondary,
+ bfd **poldbfd,
+ bfd_boolean *dynsym)
+ {
+@@ -1608,8 +1626,9 @@ _bfd_elf_add_default_symbol (bfd *abfd,
+ size_change_ok = FALSE;
+ tmp_sec = sec;
+ if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value,
+- &hi, poldbfd, NULL, NULL, &skip, &override,
+- &type_change_ok, &size_change_ok))
++ &hi, oldsecondary, poldbfd, NULL, NULL,
++ &skip, &override, &type_change_ok
++ , &size_change_ok))
+ return FALSE;
+
+ if (skip)
+@@ -1723,8 +1742,8 @@ nondefault:
+ size_change_ok = FALSE;
+ tmp_sec = sec;
+ if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value,
+- &hi, poldbfd, NULL, NULL, &skip, &override,
+- &type_change_ok, &size_change_ok))
++ &hi, oldsecondary, poldbfd, NULL, NULL, &skip,
++ &override, &type_change_ok, &size_change_ok))
+ return FALSE;
+
+ if (skip)
+@@ -2868,31 +2887,41 @@ _bfd_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
+ return tls;
+ }
+
+-/* Return TRUE iff this is a non-common, definition of a non-function symbol. */
++/* Return TRUE iff this is a non-common, definition of a
++ non-function symbol, unless IGNORE_SECONDARY is TRUE. */
++
+ static bfd_boolean
+-is_global_data_symbol_definition (bfd *abfd ATTRIBUTE_UNUSED,
+- Elf_Internal_Sym *sym)
++is_global_symbol_definition (bfd *abfd, Elf_Internal_Sym *sym,
++ bfd_boolean ignore_secondary)
+ {
+- const struct elf_backend_data *bed;
++ /* Ignore secondary symbols. */
++ if (ignore_secondary && ELF_ST_BIND (sym->st_info) == STB_SECONDARY)
++ return FALSE;
+
+ /* Local symbols do not count, but target specific ones might. */
+ if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL
+ && ELF_ST_BIND (sym->st_info) < STB_LOOS)
+ return FALSE;
+
+- bed = get_elf_backend_data (abfd);
+- /* Function symbols do not count. */
+- if (bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
+- return FALSE;
+-
+ /* If the section is undefined, then so is the symbol. */
+ if (sym->st_shndx == SHN_UNDEF)
+ return FALSE;
+
+- /* If the symbol is defined in the common section, then
+- it is a common definition and so does not count. */
+- if (bed->common_definition (sym))
+- return FALSE;
++ /* If secondary symbols are ignored, count function and common
++ symbols as global definition. */
++ if (!ignore_secondary)
++ {
++ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
++
++ /* Function symbols do not count. */
++ if (bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
++ return FALSE;
++
++ /* If the symbol is defined in the common section, then
++ it is a common definition and so does not count. */
++ if (bed->common_definition (sym))
++ return FALSE;
++ }
+
+ /* If the symbol is in a target specific section then we
+ must rely upon the backend to tell us what it is. */
+@@ -2911,9 +2940,12 @@ is_global_data_symbol_definition (bfd *abfd ATTRIBUTE_UNUSED,
+
+ /* Search the symbol table of the archive element of the archive ABFD
+ whose archive map contains a mention of SYMDEF, and determine if
+- the symbol is defined in this element. */
++ the symbol is defined in this element. Igore seconday defintion,
++ it IGNORE_SECONDARY is TRUE. */
++
+ static bfd_boolean
+-elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
++elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef,
++ bfd_boolean ignore_secondary)
+ {
+ Elf_Internal_Shdr * hdr;
+ bfd_size_type symcount;
+@@ -2974,7 +3006,8 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
+
+ if (strcmp (name, symdef->name) == 0)
+ {
+- result = is_global_data_symbol_definition (abfd, isym);
++ result = is_global_symbol_definition (abfd, isym,
++ ignore_secondary);
+ break;
+ }
+ }
+@@ -3822,6 +3855,7 @@ error_free_dyn:
+ bfd_boolean common;
+ unsigned int old_alignment;
+ bfd *old_bfd;
++ bfd_boolean oldsecondary;
+
+ override = FALSE;
+
+@@ -3849,6 +3883,10 @@ error_free_dyn:
+ flags = BSF_WEAK;
+ break;
+
++ case STB_SECONDARY:
++ flags = BSF_SECONDARY;
++ break;
++
+ case STB_GNU_UNIQUE:
+ flags = BSF_GNU_UNIQUE;
+ break;
+@@ -4084,7 +4122,7 @@ error_free_dyn:
+ | (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
+
+ if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value,
+- sym_hash, &old_bfd, &old_weak,
++ sym_hash, FALSE, &old_bfd, &old_weak,
+ &old_alignment, &skip, &override,
+ &type_change_ok, &size_change_ok))
+ goto error_free_vers;
+@@ -4104,7 +4142,12 @@ error_free_dyn:
+ && vernum > 1
+ && definition)
+ h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1];
++
++ /* Remember if the old definition is secondary. */
++ oldsecondary = h->root.secondary != 0;
+ }
++ else
++ oldsecondary = FALSE;
+
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, name, flags, sec, value, NULL, FALSE, bed->collect,
+@@ -4184,10 +4227,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)
+@@ -4216,6 +4263,13 @@ error_free_dyn:
+ {
+ h->def_dynamic = 1;
+ hi->def_dynamic = 1;
++ /* Dynamic definition overrides regular old secondary
++ definition. */
++ if (oldsecondary)
++ {
++ h->def_regular = 0;
++ hi->def_regular = 0;
++ }
+ }
+
+ /* If the indirect symbol has been forced local, don't
+@@ -4234,7 +4288,8 @@ error_free_dyn:
+ if (definition
+ || (!override && h->root.type == bfd_link_hash_common))
+ if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym,
+- sec, value, &old_bfd, &dynsym))
++ sec, value, oldsecondary,
++ &old_bfd, &dynsym))
+ goto error_free_vers;
+
+ /* Check the alignment when a common symbol is involved. This
+@@ -5024,16 +5079,27 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
+ map alone. Instead we must read in the element's symbol
+ table and check that to see what kind of symbol definition
+ this is. */
+- if (! elf_link_is_defined_archive_symbol (abfd, symdef))
++ if (! elf_link_is_defined_archive_symbol (abfd, symdef,
++ FALSE))
+ 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)
+ /* Symbol must be defined. Don't check it again. */
+ included[i] = TRUE;
+ continue;
+ }
++ else if (h->root.secondary
++ && h->root.type == bfd_link_hash_defweak)
++ {
++ /* Ignore another secondary definition. */
++ if (! elf_link_is_defined_archive_symbol (abfd, symdef,
++ TRUE))
++ continue;
++ }
+
+ /* We need to include this archive member. */
+ element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+@@ -8807,7 +8873,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;
+@@ -8938,7 +9018,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);
+@@ -8964,10 +9045,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 1286cc1..b5c5fa2 100644
+--- a/bfd/elfn32-mips.c
++++ b/bfd/elfn32-mips.c
+@@ -3262,7 +3262,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 abdf5b0..9cb5cc4 100644
+--- a/bfd/linker.c
++++ b/bfd/linker.c
+@@ -1444,6 +1444,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
+ struct bfd_link_hash_entry *h;
+ struct bfd_link_hash_entry *inh = NULL;
+ bfd_boolean cycle;
++ unsigned int secondary;
+
+ BFD_ASSERT (section != NULL);
+
+@@ -1508,15 +1509,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:
+@@ -1561,6 +1600,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 a1d1d77..6077121 100644
+--- a/bfd/syms.c
++++ b/bfd/syms.c
+@@ -306,6 +306,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
+@@ -489,6 +493,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' : ' ',
+@@ -692,6 +697,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 ecd147e..300fd13 100644
+--- a/binutils/nm.c
++++ b/binutils/nm.c
+@@ -444,6 +444,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 7463c55..6596a21 100644
+--- a/binutils/readelf.c
++++ b/binutils/readelf.c
+@@ -9262,6 +9262,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), _("<processor specific>: %d"),
+diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
+index e2ef99e..ab61461 100644
+--- a/gas/config/obj-elf.c
++++ b/gas/config/obj-elf.c
+@@ -68,6 +68,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);
+@@ -97,6 +98,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},
+@@ -443,6 +445,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;
+@@ -452,7 +477,8 @@ obj_elf_weak (int ignore ATTRIBUTE_UNUSED)
+ {
+ symbolP = get_sym_from_input_line_and_check ();
+ c = *input_line_pointer;
+- S_SET_WEAK (symbolP);
++ if (!S_IS_SECONDARY (symbolP))
++ S_SET_WEAK (symbolP);
+ if (c == ',')
+ {
+ input_line_pointer++;
+@@ -2194,18 +2220,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
+@@ -2419,7 +2451,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 251b6d5..0cf993d 100644
+--- a/gas/doc/as.texinfo
++++ b/gas/doc/as.texinfo
+@@ -4270,6 +4270,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}}
+@@ -5952,6 +5953,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 6af8604..87f22d6 100644
+--- a/gas/symbols.c
++++ b/gas/symbols.c
+@@ -2033,6 +2033,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))
+@@ -2079,7 +2087,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
+@@ -2215,9 +2223,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)
+@@ -2240,7 +2248,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] != '.')
+@@ -2253,13 +2261,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
+@@ -2271,7 +2279,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
+@@ -2328,6 +2345,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 4c83033..f765aec 100644
+--- a/gas/symbols.h
++++ b/gas/symbols.h
+@@ -91,6 +91,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 *);
+@@ -109,6 +110,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 f17f7e0..65bb3c5 100644
+--- a/gas/testsuite/gas/elf/elf.exp
++++ b/gas/testsuite/gas/elf/elf.exp
+@@ -203,6 +203,11 @@ if { [is_elf_format] } then {
+
+ run_dump_test "common1"
+ run_dump_test "common2"
++ run_dump_test "common3"
++ run_dump_test "common4"
++
++ run_elf_list_test "secondary1" "" "" "-s" "| grep \"secondary_\""
++ run_elf_list_test "secondary2" "" "" "-s" "| grep \"secondary_\""
+
+ load_lib gas-dg.exp
+ dg-init
+diff --git a/gas/testsuite/gas/elf/secondary1.e b/gas/testsuite/gas/elf/secondary1.e
+new file mode 100644
+index 0000000..da00dfb
+--- /dev/null
++++ b/gas/testsuite/gas/elf/secondary1.e
+@@ -0,0 +1,4 @@
++ +.: 0+0 +1 +FUNC +SECOND +DEFAULT +. secondary_function1
++ +.: 0+1 +1 +FUNC +SECOND +DEFAULT +. secondary_function2
++ +.: 0+0 +1 +OBJECT +SECOND +DEFAULT +. secondary_object1
++ +.: 0+1 +1 +OBJECT +SECOND +DEFAULT +. secondary_object2
+diff --git a/gas/testsuite/gas/elf/secondary1.s b/gas/testsuite/gas/elf/secondary1.s
+new file mode 100644
+index 0000000..6a3032d
+--- /dev/null
++++ b/gas/testsuite/gas/elf/secondary1.s
+@@ -0,0 +1,33 @@
++ .text
++
++ .size secondary_function1,1
++ .secondary secondary_function1
++ .weak secondary_function1
++ .type secondary_function1,%function
++secondary_function1:
++ .byte 0x0
++ .size secondary_function1,1
++
++ .size secondary_function2,1
++ .weak secondary_function2
++ .secondary secondary_function2
++ .type secondary_function2,%function
++secondary_function2:
++ .byte 0x0
++ .size secondary_function2,1
++
++
++ .data
++ .type secondary_object1,%object
++ .weak secondary_object1
++ .secondary secondary_object1
++secondary_object1:
++ .byte 0x0
++ .size secondary_object1,1
++
++ .type secondary_object2,%object
++ .weak secondary_object2
++ .secondary secondary_object2
++secondary_object2:
++ .byte 0x0
++ .size secondary_object2,1
+diff --git a/gas/testsuite/gas/elf/secondary2.e b/gas/testsuite/gas/elf/secondary2.e
+new file mode 100644
+index 0000000..0470eb8
+--- /dev/null
++++ b/gas/testsuite/gas/elf/secondary2.e
+@@ -0,0 +1 @@
++ +.: 0+ +0 +[A-Z]+ +WEAK +DEFAULT +UND secondary_function
+diff --git a/gas/testsuite/gas/elf/secondary2.s b/gas/testsuite/gas/elf/secondary2.s
+new file mode 100644
+index 0000000..234330a
+--- /dev/null
++++ b/gas/testsuite/gas/elf/secondary2.s
+@@ -0,0 +1,5 @@
++ .text
++ .secondary secondary_function
++ .dc.a secondary_function
++ .data
++ .secondary secondary_object
+diff --git a/gas/testsuite/gas/elf/type.e b/gas/testsuite/gas/elf/type.e
+index a1159bf..d4c0548 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 125683d..5565050 100644
+--- a/include/bfdlink.h
++++ b/include/bfdlink.h
+@@ -93,6 +93,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
+ {
+@@ -355,6 +358,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 e8ae3ac..b1e66d4 100644
+--- a/include/elf/common.h
++++ b/include/elf/common.h
+@@ -664,6 +664,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 67c437d..d842c5d 100644
+--- a/ld/emultempl/elf32.em
++++ b/ld/emultempl/elf32.em
+@@ -2326,6 +2326,8 @@ fragment <<EOF
+ link_info.error_textrel = FALSE;
+ else if (strcmp (optarg, "textoff") == 0)
+ link_info.error_textrel = FALSE;
++ else if (strcmp (optarg, "nosecondary") == 0)
++ link_info.emit_secondary = FALSE;
+ EOF
+ fi
+
+@@ -2453,6 +2455,8 @@ fragment <<EOF
+ -z relro Create RELRO program header\n"));
+ fprintf (file, _("\
+ -z stacksize=SIZE Set size of stack segment\n"));
++ fprintf (file, _("\
++ -z nosecondary Convert secondary symbols to weak symbols\n"));
+ EOF
+ fi
+
+diff --git a/ld/ld.texinfo b/ld/ld.texinfo
+index e71be5e..30dddd4 100644
+--- a/ld/ld.texinfo
++++ b/ld/ld.texinfo
+@@ -1121,6 +1121,10 @@ Marks the object may contain $ORIGIN.
+ @item relro
+ Create an ELF @code{PT_GNU_RELRO} segment header in the object.
+
++@item nosecondary
++Convert secondary symbols to weak symbols when generating a shared
++library.
++
+ @item max-page-size=@var{value}
+ Set the emulation maximum page size to @var{value}.
+
+diff --git a/ld/ldmain.c b/ld/ldmain.c
+index 77235d5..096ce2e 100644
+--- a/ld/ldmain.c
++++ b/ld/ldmain.c
+@@ -279,6 +279,7 @@ main (int argc, char **argv)
+ link_info.combreloc = TRUE;
+ link_info.strip_discarded = TRUE;
+ link_info.emit_hash = TRUE;
++ link_info.emit_secondary = TRUE;
+ link_info.callbacks = &link_callbacks;
+ link_info.input_bfds_tail = &link_info.input_bfds;
+ /* SVR4 linkers seem to set DT_INIT and DT_FINI based on magic _init
+diff --git a/ld/testsuite/ld-elf/library1.c b/ld/testsuite/ld-elf/library1.c
+new file mode 100644
+index 0000000..28e255d
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library1.c
+@@ -0,0 +1,11 @@
++#include <stdio.h>
++
++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 <stdio.h>
++
++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/library5a.c b/ld/testsuite/ld-elf/library5a.c
+new file mode 100644
+index 0000000..7e44bb4
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library5a.c
+@@ -0,0 +1,16 @@
++#include <stdio.h>
++
++asm (".secondary bar");
++asm (".weak bar");
++
++void
++bar (void)
++{
++ printf ("secondary bar\n");
++}
++
++void
++xxx (void)
++{
++ printf ("xxx\n");
++}
+diff --git a/ld/testsuite/ld-elf/library5b.c b/ld/testsuite/ld-elf/library5b.c
+new file mode 100644
+index 0000000..f44d97c
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library5b.c
+@@ -0,0 +1,10 @@
++#include <stdio.h>
++
++extern void bar (void);
++
++void
++foo (void)
++{
++ printf ("foo\n");
++ bar ();
++}
+diff --git a/ld/testsuite/ld-elf/library6a.c b/ld/testsuite/ld-elf/library6a.c
+new file mode 100644
+index 0000000..7de81b3
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library6a.c
+@@ -0,0 +1,4 @@
++void
++bar (void)
++{
++}
+diff --git a/ld/testsuite/ld-elf/library6b.c b/ld/testsuite/ld-elf/library6b.c
+new file mode 100644
+index 0000000..528fd89
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library6b.c
+@@ -0,0 +1,7 @@
++extern void bar (void);
++
++void
++xxx (void)
++{
++ bar ();
++}
+diff --git a/ld/testsuite/ld-elf/library6c.c b/ld/testsuite/ld-elf/library6c.c
+new file mode 100644
+index 0000000..60f4b92
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library6c.c
+@@ -0,0 +1,9 @@
++extern void abort (void);
++
++asm (".secondary bar");
++
++void
++bar (void)
++{
++ abort ();
++}
+diff --git a/ld/testsuite/ld-elf/library7a.c b/ld/testsuite/ld-elf/library7a.c
+new file mode 100644
+index 0000000..10cd8bf
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library7a.c
+@@ -0,0 +1 @@
++int bar;
+diff --git a/ld/testsuite/ld-elf/library7b.c b/ld/testsuite/ld-elf/library7b.c
+new file mode 100644
+index 0000000..5f67848
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library7b.c
+@@ -0,0 +1,7 @@
++extern int bar;
++
++int
++xxx (void)
++{
++ return bar;
++}
+diff --git a/ld/testsuite/ld-elf/library7c.c b/ld/testsuite/ld-elf/library7c.c
+new file mode 100644
+index 0000000..aa57fde
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library7c.c
+@@ -0,0 +1,3 @@
++asm (".secondary bar");
++
++int bar = 3;
+diff --git a/ld/testsuite/ld-elf/library8.map b/ld/testsuite/ld-elf/library8.map
+new file mode 100644
+index 0000000..bcbb4de
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8.map
+@@ -0,0 +1,4 @@
++VERS_1 {
++ global: bar; _bar;
++ local: *;
++};
+diff --git a/ld/testsuite/ld-elf/library8a.c b/ld/testsuite/ld-elf/library8a.c
+new file mode 100644
+index 0000000..29a7508
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8a.c
+@@ -0,0 +1,10 @@
++#if 1
++asm (".secondary bar");
++#else
++asm (".weak bar");
++#endif
++
++void
++bar (void)
++{
++}
+diff --git a/ld/testsuite/ld-elf/library8a.rd b/ld/testsuite/ld-elf/library8a.rd
+new file mode 100644
+index 0000000..a593fbd
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8a.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +FUNC +SECOND +DEFAULT +[0-9]+ +_?bar@@VERS_1
++#...
+diff --git a/ld/testsuite/ld-elf/library8b.c b/ld/testsuite/ld-elf/library8b.c
+new file mode 100644
+index 0000000..7de81b3
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8b.c
+@@ -0,0 +1,4 @@
++void
++bar (void)
++{
++}
+diff --git a/ld/testsuite/ld-elf/library8b.rd b/ld/testsuite/ld-elf/library8b.rd
+new file mode 100644
+index 0000000..fc18d1a
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8b.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +FUNC +GLOBAL +DEFAULT +[0-9]+ +_?bar@@VERS_1
++#...
+diff --git a/ld/testsuite/ld-elf/library8c.c b/ld/testsuite/ld-elf/library8c.c
+new file mode 100644
+index 0000000..dfb6a22
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8c.c
+@@ -0,0 +1,7 @@
++extern void bar ();
++
++void
++foo (void)
++{
++ bar ();
++}
+diff --git a/ld/testsuite/ld-elf/library8c.rd b/ld/testsuite/ld-elf/library8c.rd
+new file mode 100644
+index 0000000..317631f
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8c.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +0+ +0+ +FUNC +GLOBAL +DEFAULT +UND +_?bar@@VERS_1
++#...
+diff --git a/ld/testsuite/ld-elf/secondary-foo.c b/ld/testsuite/ld-elf/secondary-foo.c
+new file mode 100644
+index 0000000..8b23ec8
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary-foo.c
+@@ -0,0 +1,7 @@
++extern void bar (void);
++
++void
++foo (void)
++{
++ bar ();
++}
+diff --git a/ld/testsuite/ld-elf/secondary-main.c b/ld/testsuite/ld-elf/secondary-main.c
+new file mode 100644
+index 0000000..f1cb6b4
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary-main.c
+@@ -0,0 +1,8 @@
++extern void foo (void);
++
++int
++main (void)
++{
++ foo ();
++ 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 <stdio.h>
++
++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..5143262
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary.exp
+@@ -0,0 +1,176 @@
++# 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 secondary1.o"
++ "-r -nostdlib" ""
++ {secondary.c} {{readelf {-s} secondary.rd}} "secondary1.o"}
++ {"Build secondary1.so"
++ "-Wl,-z,nosecondary -shared" "-fPIC"
++ {secondary.c} {{readelf {--dyn-syms} secondary1.rd}} "secondary1.so"}
++ {"Build secondary2.so"
++ "-shared" "-fPIC"
++ {secondary.c} {{readelf {--dyn-syms} secondary2.rd}} "secondary2.so"}
++ {"Build libfoo.so"
++ "-shared" "-fPIC"
++ {secondary-foo.c} {} "libfoo.so"}
++ {"Build secondary-main with secondary.o"
++ "tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} {{readelf {--dyn-syms} secondary1.rd}} "secondary"}
++ {"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"}
++ {"Build secondary3a.o"
++ "" ""
++ {secondary3a.s} {} "secondary3a.a"}
++ {"Build secondary3"
++ "-nostdlib tmpdir/secondary3a.o" ""
++ {secondary3b.s} {{readelf {-s} secondary3.rd}} "secondary3"}
++ {"Build secondary4.so"
++ "-nostdlib -shared tmpdir/secondary3a.o" ""
++ {secondary4.s} {{readelf {--dyn-syms} secondary4.rd}} "secondary4.so"}
++ {"Build library5a.a"
++ "" ""
++ {library5a.c} {} "library5a.a"}
++ {"Build library5b.a"
++ "" ""
++ {library5b.c} {} "library5b.a"}
++ {"Build secondary5.a"
++ "" ""
++ {secondary5.c} {} "secondary5.a"}
++ {"Build library6a.a"
++ "" ""
++ {library6a.c} {} "library6a.a"}
++ {"Build library6b.a"
++ "" ""
++ {library6b.c} {} "library6b.a"}
++ {"Build library6c.a"
++ "" ""
++ {library6c.c} {} "library6c.a"}
++ {"Build secondary6.a"
++ "" ""
++ {secondary6.c} {} "secondary6.a"}
++ {"Build library7a.a"
++ "" ""
++ {library7a.c} {} "library7a.a"}
++ {"Build library7b.a"
++ "" ""
++ {library7b.c} {} "library7b.a"}
++ {"Build library7c.a"
++ "" ""
++ {library7c.c} {} "library7c.a"}
++ {"Build secondary7.a"
++ "" ""
++ {secondary7.c} {} "secondary7.a"}
++ {"Build library8a.so"
++ "-shared -Wl,--version-script=library8.map" "-fPIC"
++ {library8a.c} {{readelf {-s} library8a.rd}} "library8a.so"}
++ {"Build library8b.so"
++ "-shared -Wl,--version-script=library8.map" "-fPIC"
++ {library8b.c} {{readelf {-s} library8b.rd}} "library8b.so"}
++ {"Build library8c.a"
++ "" "-fPIC"
++ {library8c.c} {} "library8c.a"}
++ {"Build library8c.so"
++ "-shared -Wl,--version-script=library8.map tmpdir/library8c.o tmpdir/library8a.so tmpdir/library8b.so"
++ "-fPIC"
++ {dummy.c} {{readelf {-s} library8c.rd}} "library8c.so"}
++}
++
++run_cc_link_tests $build_tests
++
++set run_tests {
++ {"Run secondary-main with secondary.o"
++ "tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary1" "secondary1.out"}
++ {"Run secondary-main with secondary1.so"
++ "tmpdir/secondary1.so tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary2" "secondary1.out"}
++ {"Run secondary-main with secondary.o library1.o"
++ "tmpdir/secondary.o tmpdir/secondary.o tmpdir/library1.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary3" "library1.out"}
++ {"Run secondary-main with library1.o secondary.o"
++ "tmpdir/library1.o tmpdir/secondary.o tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary4" "library1.out"}
++ {"Run secondary-main with secondary.o library2.o"
++ "tmpdir/secondary.o tmpdir/library2.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary5" "library2.out"}
++ {"Run secondary-main with library2.o secondary.o"
++ "tmpdir/library2.o tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary6" "library2.out"}
++ {"Run secondary-main with secondary.o library1.so"
++ "tmpdir/secondary.o tmpdir/library1.so tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary7" "library3.out"}
++ {"Run secondary-main with library1.so secondary.o"
++ "tmpdir/library1.so tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary8" "library3.out"}
++ {"Run secondary-main with secondary.o library2.so"
++ "tmpdir/secondary.o tmpdir/library2.so tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary9" "library4.out"}
++ {"Run secondary-main with library2.so secondary.o"
++ "tmpdir/library2.so tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary10" "library4.out"}
++ {"Run secondary5 with library5a.a library5b.a"
++ "tmpdir/secondary5.o tmpdir/library5a.a tmpdir/library5b.a" ""
++ {dummy.c} "secondary5a" "secondary5.out"}
++ {"Run secondary5 with -( library5a.a library5b.a -)"
++ "tmpdir/secondary5.o -\\( tmpdir/library5a.a tmpdir/library5b.a -\\)" ""
++ {dummy.c} "secondary5b" "secondary5.out"}
++ {"Run secondary5 with -( library5a.a library5b.a -) -( library5a.a library5b.a -)"
++ "tmpdir/secondary5.o -\\( tmpdir/library5a.a tmpdir/library5b.a -\\) -\\( tmpdir/library5a.a tmpdir/library5b.a -\\)" ""
++ {dummy.c} "secondary5c" "secondary5.out"}
++ {"Run secondary6 with -( library6a.a library6b.a library6c.a -)"
++ "tmpdir/secondary6.o -\\( tmpdir/library6a.a tmpdir/library6b.a tmpdir/library6c.a -\\)" ""
++ {dummy.c} "secondary6" "secondary6.out"}
++ {"Run secondary7 with -( library7a.a library7b.a library7c.a -)"
++ "tmpdir/secondary7.o -\\( tmpdir/library7a.a tmpdir/library7b.a tmpdir/library7c.a -\\)" ""
++ {dummy.c} "secondary7" "secondary7.out"}
++}
++
++run_ld_link_exec_tests [] $run_tests
+diff --git a/ld/testsuite/ld-elf/secondary.rd b/ld/testsuite/ld-elf/secondary.rd
+new file mode 100644
+index 0000000..9931c04
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.symtab' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +FUNC +SECOND +DEFAULT +[0-9]+ +_?bar
++#...
+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
+diff --git a/ld/testsuite/ld-elf/secondary1.rd b/ld/testsuite/ld-elf/secondary1.rd
+new file mode 100644
+index 0000000..89d6d76
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary1.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +FUNC +WEAK +DEFAULT +[0-9]+ +_?bar
++#...
+diff --git a/ld/testsuite/ld-elf/secondary2.rd b/ld/testsuite/ld-elf/secondary2.rd
+new file mode 100644
+index 0000000..ff618a0
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary2.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +FUNC +SECOND +DEFAULT +[0-9]+ +_?bar
++#...
+diff --git a/ld/testsuite/ld-elf/secondary3.rd b/ld/testsuite/ld-elf/secondary3.rd
+new file mode 100644
+index 0000000..93c3469
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary3.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.symtab' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +0+ +0+ +[A-Z]+ +WEAK +DEFAULT +UND +_?foo
++#...
+diff --git a/ld/testsuite/ld-elf/secondary3a.s b/ld/testsuite/ld-elf/secondary3a.s
+new file mode 100644
+index 0000000..16a1300
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary3a.s
+@@ -0,0 +1,4 @@
++ .section .text,"axG",%progbits,foo_group,comdat
++ .global bar
++bar:
++ .byte 0
+diff --git a/ld/testsuite/ld-elf/secondary3b.s b/ld/testsuite/ld-elf/secondary3b.s
+new file mode 100644
+index 0000000..cc6f37b
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary3b.s
+@@ -0,0 +1,20 @@
++ .section .text,"axG",%progbits,foo_group,comdat
++ .secondary foo
++ .global bar
++foo:
++ .byte 0
++bar:
++ .byte 0
++ .data
++ .dc.a foo
++
++ .text
++ .global start /* Used by SH targets. */
++start:
++ .global _start
++_start:
++ .global __start
++__start:
++ .global main /* Used by HPPA targets. */
++main:
++ .dc.a bar
+diff --git a/ld/testsuite/ld-elf/secondary4.rd b/ld/testsuite/ld-elf/secondary4.rd
+new file mode 100644
+index 0000000..e84b1a6
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary4.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +0+ +0+ +[A-Z]+ +WEAK +DEFAULT +UND +_?foo
++#...
+diff --git a/ld/testsuite/ld-elf/secondary4.s b/ld/testsuite/ld-elf/secondary4.s
+new file mode 100644
+index 0000000..a2acf21
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary4.s
+@@ -0,0 +1,9 @@
++ .section .text,"axG",%progbits,foo_group,comdat
++ .secondary foo
++ .global bar
++foo:
++ .byte 0
++bar:
++ .byte 0
++ .data
++ .dc.a foo
+diff --git a/ld/testsuite/ld-elf/secondary5.c b/ld/testsuite/ld-elf/secondary5.c
+new file mode 100644
+index 0000000..a2b2f20
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary5.c
+@@ -0,0 +1,10 @@
++extern void foo (void);
++extern void xxx (void);
++
++int
++main (void)
++{
++ foo ();
++ xxx ();
++ return 0;
++}
+diff --git a/ld/testsuite/ld-elf/secondary5.out b/ld/testsuite/ld-elf/secondary5.out
+new file mode 100644
+index 0000000..730c35d
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary5.out
+@@ -0,0 +1,3 @@
++foo
++secondary bar
++xxx
+diff --git a/ld/testsuite/ld-elf/secondary6.c b/ld/testsuite/ld-elf/secondary6.c
+new file mode 100644
+index 0000000..2a7e17b
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary6.c
+@@ -0,0 +1,11 @@
++#include <stdio.h>
++
++extern void xxx (void);
++
++int
++main (void)
++{
++ xxx ();
++ printf ("OK\n");
++ return 0;
++}
+diff --git a/ld/testsuite/ld-elf/secondary6.out b/ld/testsuite/ld-elf/secondary6.out
+new file mode 100644
+index 0000000..d86bac9
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary6.out
+@@ -0,0 +1 @@
++OK
+diff --git a/ld/testsuite/ld-elf/secondary7.c b/ld/testsuite/ld-elf/secondary7.c
+new file mode 100644
+index 0000000..9a67352
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary7.c
+@@ -0,0 +1,13 @@
++#include <stdio.h>
++
++extern void abort (void);
++extern int xxx (void);
++
++int
++main (void)
++{
++ if (xxx () != 0)
++ abort ();
++ printf ("OK\n");
++ return 0;
++}
+diff --git a/ld/testsuite/ld-elf/secondary7.out b/ld/testsuite/ld-elf/secondary7.out
+new file mode 100644
+index 0000000..d86bac9
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary7.out
+@@ -0,0 +1 @@
++OK
+--
+1.9.3
+