From: H.J. Lu Date: Mon, 4 Nov 2013 18:52:13 +0000 (-0800) Subject: Add binutils-secondary.patch X-Git-Tag: hjl/linux/release/2.24.51.0.2~3^2~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a1ca47c64aa2ffccaac9cac047b1c933919f87b9;p=thirdparty%2Fbinutils-gdb.git Add binutils-secondary.patch --- diff --git a/patches/README b/patches/README index 2c295492d87..1bd52a93631 100644 --- a/patches/README +++ b/patches/README @@ -19,6 +19,7 @@ patches=" binutils-sharable.patch binutils-lto-mixed.patch binutils-pr12639.patch + binutils-secondary.patch " for p in $patches diff --git a/patches/binutils-secondary.patch b/patches/binutils-secondary.patch new file mode 100644 index 00000000000..a74f6e711d0 --- /dev/null +++ b/patches/binutils-secondary.patch @@ -0,0 +1,2196 @@ +From 8e0199c4452810eb9f95363410777407e922651f Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +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 ++ ++ * 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 ++ ++ * 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 ++ ++ * 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 ++ ++ * elflink.c (elf_link_output_extsym): Generate STB_SECONDARY ++ symbols if needed. ++ ++2012-06-30 H.J. Lu ++ ++ * elf.c (swap_out_syms): Output undefined secondary symbols ++ as weak. ++ ++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): 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 ++ ++ * 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-09-05 H.J. Lu ++ ++ * config/obj-elf.c (obj_elf_weak): Don't set symbol weak on ++ secondary symbol. ++ ++2012-06-30 H.J. Lu ++ ++ * config/obj-elf.c (elf_frob_symbol): Handle secondary symbol ++ for .symver. Also remove the unused secondary symbol. ++ ++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): Also check secondary symbols. ++ ++ * doc/as.texinfo: Document .secondary directive. ++ ++gas/testsuite/ ++ ++2012-09-05 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/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 ++ ++ * bfdlink.h (bfd_link_info): Add emit_secondary. ++ ++2012-06-30 H.J. Lu ++ ++ * bfdlink.h (bfd_link_hash_entry): Add secondary. ++ ++include/elf/ ++ ++2012-06-30 H.J. Lu ++ ++ * common.h (STB_SECONDARY): New. ++ ++ld/ ++ ++2012-09-08 H.J. Lu ++ ++ * 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 ++ ++ * 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 ++ ++ * ld-elf/secondary.exp: Update -Wl,-z,secondary with ++ -Wl,-z,nosecondary. ++ ++2012-09-06 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/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 32b07a7..1ed4148 100644 +--- a/bfd/archive.c ++++ b/bfd/archive.c +@@ -2336,6 +2336,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 644f89d..481ebf2 100644 +--- a/bfd/bfd-in2.h ++++ b/bfd/bfd-in2.h +@@ -5898,6 +5898,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 8df38ee..b4b737d 100644 +--- a/bfd/elf.c ++++ b/bfd/elf.c +@@ -3250,7 +3250,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))); + } +@@ -6875,8 +6878,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); +@@ -6890,6 +6894,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 eec2ef7..4c3cd23 100644 +--- a/bfd/elf32-mips.c ++++ b/bfd/elf32-mips.c +@@ -2155,7 +2155,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 102cdff..58e6363 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 e296c5c..05e4a90 100644 +--- a/bfd/elfcode.h ++++ b/bfd/elfcode.h +@@ -1282,6 +1282,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 1e6abd9..4f2da25 100644 +--- a/bfd/elflink.c ++++ b/bfd/elflink.c +@@ -906,7 +906,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, +@@ -916,6 +917,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, +@@ -931,7 +933,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; +@@ -989,9 +991,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; +@@ -1022,7 +1032,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; +@@ -1273,7 +1283,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. */ +@@ -1388,10 +1398,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)))) +@@ -1430,8 +1444,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 +@@ -1459,18 +1474,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 +@@ -1573,8 +1590,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, +@@ -1584,6 +1601,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) + { +@@ -1628,8 +1646,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) +@@ -1737,8 +1756,8 @@ nondefault: + size_change_ok = FALSE; + tmp_sec = sec; + if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value, +- &hi, NULL, NULL, NULL, &skip, &override, +- &type_change_ok, &size_change_ok)) ++ &hi, oldsecondary, NULL, NULL, NULL, &skip, ++ &override, &type_change_ok, &size_change_ok)) + return FALSE; + + if (skip) +@@ -2880,31 +2899,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. */ +@@ -2923,9 +2952,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; +@@ -2993,7 +3025,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; + } + } +@@ -3835,6 +3868,7 @@ error_free_dyn: + bfd_boolean common; + unsigned int old_alignment; + bfd *old_bfd; ++ bfd_boolean oldsecondary; + + override = FALSE; + +@@ -3862,6 +3896,10 @@ error_free_dyn: + flags = BSF_WEAK; + break; + ++ case STB_SECONDARY: ++ flags = BSF_SECONDARY; ++ break; ++ + case STB_GNU_UNIQUE: + flags = BSF_GNU_UNIQUE; + break; +@@ -4087,7 +4125,7 @@ error_free_dyn: + } + + 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; +@@ -4107,7 +4145,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, +@@ -4187,10 +4230,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) +@@ -4219,6 +4266,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 +@@ -4237,7 +4291,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 +@@ -5038,15 +5093,26 @@ 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) + defined[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); +@@ -8830,7 +8896,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; +@@ -8961,7 +9041,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); +@@ -8987,10 +9068,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 2daf79e..3aaaaea 100644 +--- a/bfd/elfn32-mips.c ++++ b/bfd/elfn32-mips.c +@@ -3263,7 +3263,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 190520a..d6a996b 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 27b40eb..8a58921 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 156194f..d9f4792 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 0389f14..13d1722 100644 +--- a/binutils/readelf.c ++++ b/binutils/readelf.c +@@ -9035,6 +9035,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 3377261..36461b0 100644 +--- a/gas/config/obj-elf.c ++++ b/gas/config/obj-elf.c +@@ -70,6 +70,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); +@@ -99,6 +100,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}, +@@ -445,6 +447,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; +@@ -454,7 +479,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++; +@@ -2136,18 +2162,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 +@@ -2362,7 +2394,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 9843574..f8125bd 100644 +--- a/gas/doc/as.texinfo ++++ b/gas/doc/as.texinfo +@@ -4189,6 +4189,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}} +@@ -5871,6 +5872,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 67fc84b..a8c216a 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 4196fd7..2833b6e 100644 +--- a/gas/testsuite/gas/elf/elf.exp ++++ b/gas/testsuite/gas/elf/elf.exp +@@ -209,6 +209,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 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 1ac0738..6675a12 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 cd3bcdd..ad44ad3 100644 +--- a/include/elf/common.h ++++ b/include/elf/common.h +@@ -667,6 +667,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 682f5e5..7093f2e 100644 +--- a/ld/emultempl/elf32.em ++++ b/ld/emultempl/elf32.em +@@ -2349,6 +2349,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/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 ++ ++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 ++ ++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 ++ ++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 ++ ++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 ++ ++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.8.3.1 +