summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2013-11-04 09:35:07 -0800
committerH.J. Lu <hjl.tools@gmail.com>2015-09-17 05:24:15 -0700
commitef1ce0a3648bd8d6b086bf3e05143a187d5b807f (patch)
tree9a44a8cef2bb3d6ad93906129ff6636ed624833b
parentd78908cff50f281dab6390646fb1b7c58236d83e (diff)
downloadbinutils-gdb-users/hjl/secondary.tar.gz
Add STB_SECONDARY supportusers/hjl/secondary
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. bfd/ * 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): Output undefined secondary symbols as weak. Output defined secondary symbols. * elf64-ia64-vms.c (elf64_vms_link_add_object_symbols): Handle secondary symbols. * elfcode.h (elf_slurp_symbol_table): Likewise. * 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. Allow overriding secondary symbols. (_bfd_elf_add_default_symbol): Add a boolean argument to if the old definition is secondary. Handle the unversioned STB_SECONDARY symbol with the versioned definition. * elflink.c (is_global_data_symbol_definition): Renamed to ... (is_global_symbol_definition): This. Add an argument to ignore secondary symbols. If secondary symbols are ignored, count function and common symbols as global definition. (elf_link_is_defined_archive_symbol): Add an argument to ignore secondary symbols. Updated. (elf_link_add_object_symbols): Treat secondary symbols as weak symbols. Allow overriding secondary symbols. Pass oldsecondary to _bfd_elf_merge_symbol and _bfd_elf_add_default_symbol. (elf_link_add_archive_symbols): Keep searching if a definition is secondary. Ignore another secondary definition. Updated. (elf_link_output_extsym): Generate STB_SECONDARY symbols if needed. * linker.c (_bfd_generic_link_add_one_symbol): Treat secondary symbol as weak symbol. Mark secondary symbol. * syms.c (BSF_SECONDARY): New. (bfd_print_symbol_vandf): Handle SECONDARY symbol. (bfd_decode_symclass): Likewise. * bfd-in2.h: Regenerated. binutils/ * nm.c (filter_symbols): Treat BSF_SECONDARY symbol as global. * readelf.c (get_symbol_binding): Handle STB_SECONDARY. gas/ * 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". (obj_elf_weak): Don't set symbol weak on secondary symbol. (elf_frob_symbol): Check secondary symbol. Handle secondary symbol for .symver. Also remove the unused secondary symbol. (elf_frob_file_before_adjust): Treat secondary symbols as weak. * doc/as.texinfo: Document .secondary directive. gas/testsuite/ * 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/ * bfdlink.h (bfd_link_hash_entry): Add secondary. (bfd_link_info): Add emit_secondary. include/elf/ * common.h (STB_SECONDARY): New. ld/ * ld.texinfo: Document "-z nosecondary". * ldmain.c (main): Initialize link_info.emit_secondary to TRUE. * lexsup.c (elf_shlib_list_options): Add "-z nosecondary". * 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". ld/testsuite/ * 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/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. * 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/secondary8a.c: Likewise. * ld-elf/secondary8a.map: Likewise. * ld-elf/secondary8a.rd: Likewise. * ld-elf/secondary8b.c: Likewise. * ld-elf/secondary8b.rd: Likewise.
-rw-r--r--bfd/archive.c1
-rw-r--r--bfd/bfd-in2.h4
-rw-r--r--bfd/elf.c10
-rw-r--r--bfd/elf32-mips.c5
-rw-r--r--bfd/elf64-ia64-vms.c4
-rw-r--r--bfd/elfcode.h3
-rw-r--r--bfd/elflink.c177
-rw-r--r--bfd/elfn32-mips.c5
-rw-r--r--bfd/linker.c44
-rw-r--r--bfd/syms.c14
-rw-r--r--binutils/nm.c1
-rw-r--r--binutils/readelf.c1
-rw-r--r--gas/config/obj-elf.c42
-rw-r--r--gas/doc/as.texinfo9
-rw-r--r--gas/symbols.c39
-rw-r--r--gas/symbols.h2
-rw-r--r--gas/testsuite/gas/elf/common3.d2
-rw-r--r--gas/testsuite/gas/elf/common3.l2
-rw-r--r--gas/testsuite/gas/elf/common3.s2
-rw-r--r--gas/testsuite/gas/elf/common4.d2
-rw-r--r--gas/testsuite/gas/elf/common4.l2
-rw-r--r--gas/testsuite/gas/elf/common4.s2
-rw-r--r--gas/testsuite/gas/elf/elf.exp5
-rw-r--r--gas/testsuite/gas/elf/secondary1.e4
-rw-r--r--gas/testsuite/gas/elf/secondary1.s33
-rw-r--r--gas/testsuite/gas/elf/secondary2.e1
-rw-r--r--gas/testsuite/gas/elf/secondary2.s5
-rw-r--r--gas/testsuite/gas/elf/type.e2
-rw-r--r--gas/testsuite/gas/elf/type.s13
-rw-r--r--include/bfdlink.h6
-rw-r--r--include/elf/common.h1
-rw-r--r--ld/emultempl/elf32.em2
-rw-r--r--ld/ld.texinfo4
-rw-r--r--ld/ldmain.c1
-rw-r--r--ld/lexsup.c2
-rw-r--r--ld/testsuite/ld-elf/library1.c11
-rw-r--r--ld/testsuite/ld-elf/library1.out1
-rw-r--r--ld/testsuite/ld-elf/library2.c12
-rw-r--r--ld/testsuite/ld-elf/library2.out1
-rw-r--r--ld/testsuite/ld-elf/library3.out1
-rw-r--r--ld/testsuite/ld-elf/library4.out1
-rw-r--r--ld/testsuite/ld-elf/library5a.c16
-rw-r--r--ld/testsuite/ld-elf/library5b.c10
-rw-r--r--ld/testsuite/ld-elf/library6a.c4
-rw-r--r--ld/testsuite/ld-elf/library6b.c7
-rw-r--r--ld/testsuite/ld-elf/library6c.c9
-rw-r--r--ld/testsuite/ld-elf/library7a.c1
-rw-r--r--ld/testsuite/ld-elf/library7b.c7
-rw-r--r--ld/testsuite/ld-elf/library7c.c3
-rw-r--r--ld/testsuite/ld-elf/library8.map4
-rw-r--r--ld/testsuite/ld-elf/library8a.c10
-rw-r--r--ld/testsuite/ld-elf/library8a.rd5
-rw-r--r--ld/testsuite/ld-elf/library8b.c4
-rw-r--r--ld/testsuite/ld-elf/library8b.rd5
-rw-r--r--ld/testsuite/ld-elf/library8c.c7
-rw-r--r--ld/testsuite/ld-elf/library8c.rd5
-rw-r--r--ld/testsuite/ld-elf/secondary-foo.c7
-rw-r--r--ld/testsuite/ld-elf/secondary-main.c8
-rw-r--r--ld/testsuite/ld-elf/secondary.c9
-rw-r--r--ld/testsuite/ld-elf/secondary.exp186
-rw-r--r--ld/testsuite/ld-elf/secondary.rd5
-rw-r--r--ld/testsuite/ld-elf/secondary1.out1
-rw-r--r--ld/testsuite/ld-elf/secondary1.rd5
-rw-r--r--ld/testsuite/ld-elf/secondary2.rd5
-rw-r--r--ld/testsuite/ld-elf/secondary3.rd6
-rw-r--r--ld/testsuite/ld-elf/secondary3a.s4
-rw-r--r--ld/testsuite/ld-elf/secondary3b.s20
-rw-r--r--ld/testsuite/ld-elf/secondary4.rd5
-rw-r--r--ld/testsuite/ld-elf/secondary4.s9
-rw-r--r--ld/testsuite/ld-elf/secondary5.c10
-rw-r--r--ld/testsuite/ld-elf/secondary5.out3
-rw-r--r--ld/testsuite/ld-elf/secondary6.c11
-rw-r--r--ld/testsuite/ld-elf/secondary6.out1
-rw-r--r--ld/testsuite/ld-elf/secondary7.c13
-rw-r--r--ld/testsuite/ld-elf/secondary7.out1
-rw-r--r--ld/testsuite/ld-elf/secondary8a.c13
-rw-r--r--ld/testsuite/ld-elf/secondary8a.map4
-rw-r--r--ld/testsuite/ld-elf/secondary8a.rd5
-rw-r--r--ld/testsuite/ld-elf/secondary8b.c13
-rw-r--r--ld/testsuite/ld-elf/secondary8b.rd5
80 files changed, 862 insertions, 63 deletions
diff --git a/bfd/archive.c b/bfd/archive.c
index 1715474ea6c..7e0a7533681 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -2372,6 +2372,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 51fa54f1d43..bb5b536e081 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -6337,6 +6337,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 35c0f6cdf43..29cfec333e3 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -3625,7 +3625,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)));
}
@@ -7408,8 +7411,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);
@@ -7423,6 +7427,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 fff08e5568d..f1755799207 100644
--- a/bfd/elf32-mips.c
+++ b/bfd/elf32-mips.c
@@ -2258,7 +2258,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 4dc5363f6bc..129413358ff 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 7e309cf998e..17f44bc0907 100644
--- a/bfd/elfcode.h
+++ b/bfd/elfcode.h
@@ -1280,6 +1280,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 8659099df0d..c4a0c1278e1 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -926,7 +926,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,
@@ -936,6 +937,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,
@@ -952,7 +954,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;
char *new_version;
@@ -1073,9 +1075,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;
@@ -1106,7 +1116,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;
@@ -1357,7 +1367,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. */
@@ -1472,10 +1482,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))))
@@ -1514,8 +1528,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
@@ -1546,18 +1561,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
@@ -1660,8 +1677,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,
@@ -1671,6 +1688,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)
{
@@ -1716,6 +1734,11 @@ _bfd_elf_add_default_symbol (bfd *abfd,
}
}
+ /* Handle the unversioned STB_SECONDARY symbol with the versioned
+ definition. */
+ if (p == NULL)
+ return TRUE;
+
bed = get_elf_backend_data (abfd);
collect = bed->collect;
dynamic = (abfd->flags & DYNAMIC) != 0;
@@ -1736,8 +1759,9 @@ _bfd_elf_add_default_symbol (bfd *abfd,
matched = TRUE;
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, &matched))
+ &hi, oldsecondary, poldbfd, NULL, NULL,
+ &skip, &override, &type_change_ok,
+ &size_change_ok, &matched))
return FALSE;
if (skip)
@@ -1856,8 +1880,9 @@ 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, &matched))
+ &hi, oldsecondary, poldbfd, NULL, NULL, &skip,
+ &override, &type_change_ok, &size_change_ok,
+ &matched))
return FALSE;
if (skip)
@@ -3003,31 +3028,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. */
@@ -3046,9 +3081,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;
@@ -3113,7 +3151,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;
}
}
@@ -3962,6 +4001,7 @@ error_free_dyn:
unsigned int old_alignment;
bfd *old_bfd;
bfd_boolean matched;
+ bfd_boolean oldsecondary;
override = FALSE;
@@ -3989,6 +4029,10 @@ error_free_dyn:
flags = BSF_WEAK;
break;
+ case STB_SECONDARY:
+ flags = BSF_SECONDARY;
+ break;
+
case STB_GNU_UNIQUE:
flags = BSF_GNU_UNIQUE;
break;
@@ -4224,7 +4268,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,
&matched))
@@ -4247,7 +4291,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,
@@ -4327,10 +4376,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)
@@ -4359,6 +4412,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
@@ -4377,7 +4437,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
@@ -5169,16 +5230,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);
@@ -9190,7 +9262,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 ((bfd_link_relocatable (flinfo->info)
+ || (!bfd_link_executable (flinfo->info)
+ && 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;
@@ -9302,7 +9388,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);
@@ -9328,10 +9415,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 (!bfd_link_relocatable (flinfo->info)
&& 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 504c3f39c69..7321f6d8261 100644
--- a/bfd/elfn32-mips.c
+++ b/bfd/elfn32-mips.c
@@ -3461,7 +3461,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 86a7a1945ba..233fc8c9d21 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:
@@ -1562,6 +1601,9 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
h->u.def.value = value;
h->linker_def = 0;
+ /* 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 9d7a1f43c13..a514efb5ded 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 ad6e70dd842..a14ff733991 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 12fb415eee7..865772af6d8 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -10002,6 +10002,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 031fafb91b4..430a4fb22c9 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},
@@ -442,6 +444,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;
@@ -451,7 +476,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++;
@@ -2211,18 +2237,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
@@ -2436,7 +2468,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 fa3221e20be..bf825e3e072 100644
--- a/gas/doc/as.texinfo
+++ b/gas/doc/as.texinfo
@@ -4335,6 +4335,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}}
@@ -6059,6 +6060,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 07362bbe1c1..24e7577060e 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 cf4f30feeca..191cad15b12 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 00000000000..e73f6c5a399
--- /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 00000000000..58d5142fc81
--- /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 00000000000..df8b7ed7f5c
--- /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 00000000000..aca59c01ad9
--- /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 00000000000..58d5142fc81
--- /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 00000000000..37bd0ce2c05
--- /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 496e01a4ff3..2db944518f8 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -211,6 +211,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_\""
run_dump_test "strtab"
diff --git a/gas/testsuite/gas/elf/secondary1.e b/gas/testsuite/gas/elf/secondary1.e
new file mode 100644
index 00000000000..da00dfb9859
--- /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 00000000000..6a3032dacd2
--- /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 00000000000..0470eb82405
--- /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 00000000000..234330ab992
--- /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 a1159bf4fbc..d4c0548b860 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 d0a1afd2fa0..bd7df2cb964 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 43bcc6a9040..e1c3d751c8e 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -99,6 +99,9 @@ struct bfd_link_hash_entry
in a linker script. */
unsigned int linker_def : 1;
+ /* Set if it is a secondary symbol. */
+ unsigned int secondary : 1;
+
/* A union of information depending upon the type. */
union
{
@@ -366,6 +369,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 e6d8c14d3a2..1e43b8e40bf 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -683,6 +683,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 7fe90894e8f..23833669386 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -2385,6 +2385,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
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index be1d4906fae..bb9408de5ee 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -1177,6 +1177,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 577928d5504..4c2b5a03440 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -278,6 +278,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/lexsup.c b/ld/lexsup.c
index 5dc56dc148e..536296d0e91 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -1732,6 +1732,8 @@ elf_shlib_list_options (FILE *file)
fprintf (file, _("\
-z norelro Don't create RELRO program header\n"));
fprintf (file, _("\
+ -z nosecondary Convert secondary symbols to weak symbols\n"));
+ fprintf (file, _("\
-z stacksize=SIZE Set size of stack segment\n"));
fprintf (file, _("\
-z text Treat DT_TEXTREL in shared object as error\n"));
diff --git a/ld/testsuite/ld-elf/library1.c b/ld/testsuite/ld-elf/library1.c
new file mode 100644
index 00000000000..28e255d318f
--- /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 00000000000..2050e746e5a
--- /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 00000000000..271ebd6ef1a
--- /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 00000000000..ddd3d10e794
--- /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 00000000000..881856e6639
--- /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 00000000000..1ff18403d51
--- /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 00000000000..7e44bb4b578
--- /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 00000000000..f44d97c2ad8
--- /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 00000000000..7de81b31a47
--- /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 00000000000..528fd893305
--- /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 00000000000..60f4b922ad4
--- /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 00000000000..10cd8bfee26
--- /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 00000000000..5f67848a29f
--- /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 00000000000..aa57fde8197
--- /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 00000000000..bcbb4dea890
--- /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 00000000000..29a75087a02
--- /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 00000000000..a593fbdc2cf
--- /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 00000000000..7de81b31a47
--- /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 00000000000..fc18d1ad625
--- /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 00000000000..dfb6a22edb8
--- /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 00000000000..e2e58f021bb
--- /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 +\([0-9]+\)
+#...
diff --git a/ld/testsuite/ld-elf/secondary-foo.c b/ld/testsuite/ld-elf/secondary-foo.c
new file mode 100644
index 00000000000..8b23ec8f2b7
--- /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 00000000000..f1cb6b492bd
--- /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 00000000000..6d64ed7652e
--- /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 00000000000..2518db3c0a0
--- /dev/null
+++ b/ld/testsuite/ld-elf/secondary.exp
@@ -0,0 +1,186 @@
+# 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"}
+ {"Build secondary8a.so"
+ "-shared -Wl,--version-script=secondary8a.map" "-fPIC"
+ {secondary8a.c} {{readelf {-s} secondary8a.rd}} "secondary8a.so"}
+ {"Build secondary8b.a"
+ "" "-fPIC"
+ {secondary8b.c} {} "secondary8b.a"}
+ {"Build secondary8b.so"
+ "-shared -Wl,--start-group tmpdir/secondary8a.so tmpdir/secondary8b.o"
+ "-fPIC"
+ {dummy.c} {{readelf {-s} secondary8b.rd}} "secondary8b.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 00000000000..9931c045b09
--- /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 00000000000..8d9378f95b4
--- /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 00000000000..89d6d76d43e
--- /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 00000000000..ff618a035ca
--- /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 00000000000..562244a0294
--- /dev/null
+++ b/ld/testsuite/ld-elf/secondary3.rd
@@ -0,0 +1,6 @@
+Symbol table '\.symtab' contains [0-9]+ entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+#failif
+#...
+ +[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 00000000000..16a130043ef
--- /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 00000000000..cc6f37bd7e2
--- /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 00000000000..e84b1a6cb86
--- /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 00000000000..a2acf21c573
--- /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 00000000000..a2b2f20695a
--- /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 00000000000..730c35dceb3
--- /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 00000000000..2a7e17b94b0
--- /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 00000000000..d86bac9de59
--- /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 00000000000..9a67352e95c
--- /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 00000000000..d86bac9de59
--- /dev/null
+++ b/ld/testsuite/ld-elf/secondary7.out
@@ -0,0 +1 @@
+OK
diff --git a/ld/testsuite/ld-elf/secondary8a.c b/ld/testsuite/ld-elf/secondary8a.c
new file mode 100644
index 00000000000..22b55aa4256
--- /dev/null
+++ b/ld/testsuite/ld-elf/secondary8a.c
@@ -0,0 +1,13 @@
+#if 1
+asm (".secondary __bar");
+asm (".secondary bar");
+#else
+asm (".weak __bar");
+asm (".weak bar");
+#endif
+
+void
+__bar (void)
+{
+}
+asm (".set bar, __bar");
diff --git a/ld/testsuite/ld-elf/secondary8a.map b/ld/testsuite/ld-elf/secondary8a.map
new file mode 100644
index 00000000000..29476406f7c
--- /dev/null
+++ b/ld/testsuite/ld-elf/secondary8a.map
@@ -0,0 +1,4 @@
+VERS_1 {
+ global: bar;
+ local: *;
+};
diff --git a/ld/testsuite/ld-elf/secondary8a.rd b/ld/testsuite/ld-elf/secondary8a.rd
new file mode 100644
index 00000000000..f52033c4dad
--- /dev/null
+++ b/ld/testsuite/ld-elf/secondary8a.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-9]+ +FUNC +SECOND +DEFAULT +[0-9]+ +_?bar@@VERS_1
+#...
diff --git a/ld/testsuite/ld-elf/secondary8b.c b/ld/testsuite/ld-elf/secondary8b.c
new file mode 100644
index 00000000000..22b55aa4256
--- /dev/null
+++ b/ld/testsuite/ld-elf/secondary8b.c
@@ -0,0 +1,13 @@
+#if 1
+asm (".secondary __bar");
+asm (".secondary bar");
+#else
+asm (".weak __bar");
+asm (".weak bar");
+#endif
+
+void
+__bar (void)
+{
+}
+asm (".set bar, __bar");
diff --git a/ld/testsuite/ld-elf/secondary8b.rd b/ld/testsuite/ld-elf/secondary8b.rd
new file mode 100644
index 00000000000..276c3ce72f5
--- /dev/null
+++ b/ld/testsuite/ld-elf/secondary8b.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 +SECOND +DEFAULT +UND +_?bar@VERS_1 +\([0-9]+\)
+#...