changeset 3875:aede79dcec2e

6516665 The link-editors should be more resilient against gcc's symbol versioning
author ab196087
date Wed, 21 Mar 2007 10:53:55 -0700
parents ceb6ac010233
children 5643dbdd82be
files usr/src/cmd/sgs/elfdump/common/elfdump.c usr/src/cmd/sgs/elfdump/common/elfdump.msg usr/src/cmd/sgs/include/conv.h usr/src/cmd/sgs/include/debug.h usr/src/cmd/sgs/include/libld.h usr/src/cmd/sgs/libconv/common/llib-lconv usr/src/cmd/sgs/libconv/common/symbols.c usr/src/cmd/sgs/libconv/common/version.c usr/src/cmd/sgs/libconv/common/version.msg usr/src/cmd/sgs/libld/common/syms.c usr/src/cmd/sgs/liblddbg/common/liblddbg.msg usr/src/cmd/sgs/liblddbg/common/llib-llddbg usr/src/cmd/sgs/liblddbg/common/mapfile-vers usr/src/cmd/sgs/liblddbg/common/syms.c usr/src/cmd/sgs/packages/common/SUNWonld-README usr/src/cmd/sgs/rtld/common/_elf.h usr/src/cmd/sgs/rtld/common/elf.c
diffstat 17 files changed, 292 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.c	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c	Wed Mar 21 10:53:55 2007 -0700
@@ -41,6 +41,49 @@
 #include	<msg.h>
 #include	<_elfdump.h>
 
+
+
+/*
+ * VERSYM_STATE is used to maintain information about the VERSYM section
+ * in the object being analyzed. It is filled in by versions(), and used
+ * by init_symtbl_state() when displaying symbol information.
+ *
+ * Note that the value of the gnu field is a hueristic guess,
+ * based on the section names.
+ */
+typedef struct {
+	Cache	*cache;		/* Pointer to cache entry for VERSYM */
+	Versym	*data;		/* Pointer to versym array */
+	int	num_verdef;	/* # of versions defined in object */
+	int	gnu;		/* True if we think obj produced by GNU tools */
+} VERSYM_STATE;
+
+/*
+ * SYMTBL_STATE is used to maintain information about a single symbol
+ * table section, for use by the routines that display symbol information.
+ */
+typedef struct {
+	const char	*file;		/* Name of file */
+	Ehdr		*ehdr;		/* ELF header for file */
+	Cache		*cache;		/* Cache of all section headers */
+	Word		shnum;		/* # of sections in cache */
+	Cache		*seccache;	/* Cache of symbol table section hdr */
+	Word		secndx;		/* Index of symbol table section hdr */
+	const char	*secname;	/* Name of section */
+	uint_t		flags;		/* Command line option flags */
+	struct {			/* Extended section index data */
+		int	checked;	/* TRUE if already checked for shxndx */
+		Word	*data;		/* NULL, or extended section index */
+					/*	used for symbol table entries */
+		uint_t	n;		/* # items in shxndx.data */
+	} shxndx;
+	VERSYM_STATE	*versym;	/* NULL, or associated VERSYM section */
+	Sym 		*sym;		/* Array of symbols */
+	Word		symn;		/* # of symbols */
+} SYMTBL_STATE;
+
+
+
 /*
  * Focal point for verifying symbol names.
  */
@@ -978,15 +1021,27 @@
 }
 
 /*
- * Search for any version sections - the Versym output is possibly used by the
- * symbols() printing.  If VERSYM is specified - then display the version
- * information.
+ * Display version section information if the flags require it.
+ * Return version information needed by other output.
+ *
+ * entry:
+ *	cache - Cache of all section headers
+ *	shnum - # of sections in cache
+ *	file - Name of file
+ *	flags - Command line option flags
+ *	versym - VERSYM_STATE block to be filled in.
  */
-static Cache *
-versions(Cache *cache, Word shnum, const char *file, uint_t flags)
+static void
+versions(Cache *cache, Word shnum, const char *file, uint_t flags,
+    VERSYM_STATE *versym)
 {
 	GElf_Word	cnt;
-	Cache		*versymcache = 0;
+	const char	*gnu_prefix;
+	size_t		gnu_prefix_len;
+
+	bzero(versym, sizeof (*versym));
+	gnu_prefix = MSG_ORIG(MSG_GNU_VERNAMPREFIX);
+	gnu_prefix_len = strlen(gnu_prefix);
 
 	for (cnt = 1; cnt < shnum; cnt++) {
 		void		*ver;
@@ -996,14 +1051,31 @@
 		const char	*secname = _cache->c_name;
 
 		/*
-		 * If this is the version symbol table simply record its
-		 * data address for possible use in later symbol processing.
+		 * If the section names starts with the .gnu.version prefix,
+		 * then this object was almost certainly produced by the
+		 * GNU ld and not the native Solaris ld.
 		 */
-		if (shdr->sh_type == SHT_SUNW_versym) {
-			versymcache = _cache;
+		if (strncmp(gnu_prefix, secname, gnu_prefix_len) == 0)
+			versym->gnu = 1;
+
+		/*
+		 * If this is the version symbol table record its data
+		 * address for later symbol processing.
+		 */
+		if ((shdr->sh_type == SHT_SUNW_versym) &&
+		    (_cache->c_data != NULL)) {
+			versym->cache = _cache;
+			versym->data = _cache->c_data->d_buf;
 			continue;
 		}
 
+		/*
+		 * If this is a version definition section, retain # of
+		 * version definitions for later symbol processing.
+		 */
+		if (shdr->sh_type == SHT_SUNW_verdef)
+			versym->num_verdef = shdr->sh_info;
+
 		if ((flags & FLG_VERSIONS) == 0)
 			continue;
 
@@ -1046,34 +1118,9 @@
 			    &cache[shdr->sh_link], file);
 		}
 	}
-	return (versymcache);
 }
 
 /*
- * SYMTBL_STATE is used to maintain information about a single symbol
- * table section, for use by the routines that display symbol information.
- */
-typedef struct {
-	const		char *file;	/* Name of file */
-	Ehdr		*ehdr;		/* ELF header for file */
-	Cache		*cache;		/* Cache of all section headers */
-	Word		shnum;		/* # of sections in cache */
-	Cache		*seccache;	/* Cache of symbol table section hdr */
-	Word		secndx;		/* Index of symbol table section hdr */
-	const char	*secname;	/* Name of section */
-	uint_t		flags;		/* Command line option flags */
-	struct {			/* Extended section index data */
-		int	checked;	/* TRUE if already checked for shxndx */
-		Word	*data;		/* NULL, or extended section index */
-					/*	used for symbol table entries */
-		uint_t	n;		/* # items in shxndx.data */
-	} shxndx;
-	Versym		*versym;	/* NULL, or versym array for symtbl */
-	Sym 		*sym;		/* Array of symbols */
-	Word		symn;		/* # of symbols */
-} SYMTBL_STATE;
-
-/*
  * Initialize a symbol table state structure
  *
  * entry:
@@ -1082,13 +1129,13 @@
  *	shnum - # of sections in cache
  *	secndx - Index of symbol table section
  *	ehdr - ELF header for file
- *	versymcache - NULL, or cache of versym section
+ *	versym - Information about versym section
  *	file - Name of file
  *	flags - Command line option flags
  */
 static int
 init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx,
-    Ehdr *ehdr, Cache *versymcache, const char *file, uint_t flags)
+    Ehdr *ehdr, VERSYM_STATE *versym, const char *file, uint_t flags)
 {
 	Shdr *shdr;
 
@@ -1134,9 +1181,9 @@
 	 * Determine if there is a associated Versym section
 	 * with this Symbol Table.
 	 */
-	if (versymcache && (versymcache->c_shdr->sh_link == state->secndx) &&
-	    versymcache->c_data)
-		state->versym = versymcache->c_data->d_buf;
+	if (versym->cache &&
+	    (versym->cache->c_shdr->sh_link == state->secndx))
+		state->versym = versym;
 	else
 		state->versym = NULL;
 
@@ -1180,12 +1227,12 @@
  * Produce a line of output for the given symbol
  *
  * entry:
+ *	state - Symbol table state
  *	symndx - Index of symbol within the table
  *	symndx_disp - Index to display. This may not be the same
  *		as symndx if the display is relative to the logical
  *		combination of the SUNW_ldynsym/dynsym tables.
  *	sym - Symbol to display
- *	state - Symbol table state
  */
 static void
 output_symbol(SYMTBL_STATE *state, Word symndx, Word disp_symndx, Sym *sym)
@@ -1209,7 +1256,7 @@
 
 	char		index[MAXNDXSIZE], *sec;
 	const char	*symname;
-	int		verndx;
+	Versym		verndx;
 	uchar_t		type;
 	Shdr		*tshdr;
 	Word		shndx;
@@ -1277,12 +1324,44 @@
 
 	/*
 	 * If versioning is available display the
-	 * version index.
+	 * version index. If not, then use 0.
 	 */
-	if (state->versym)
-		verndx = (int)state->versym[symndx];
-	else
+	if (state->versym) {
+		verndx = state->versym->data[symndx];
+
+		/*
+		 * Check to see if this is a defined symbol with a
+		 * version index that is outside the valid range for
+		 * the file. If so, then there are two possiblities:
+		 *
+		 *	- Files produced by the GNU ld use the top (16th) bit
+		 *		as a "hidden symbol" marker. If we have
+		 *		detected that this object comes from GNU ld,
+		 *		then check to see if this is the case and that
+		 *		the resulting masked version is in range. If so,
+		 *		issue a warning describing it.
+		 *	- If this is not a GNU "hidden bit" issue, then
+		 *		issue a generic "out of range" error.
+		 */
+		if (VERNDX_INVALID(sym->st_shndx, state->versym->num_verdef,
+		    state->versym->data, verndx)) {
+			if (state->versym->gnu && (verndx & 0x8000) &&
+			    ((verndx & ~0x8000) <=
+			    state->versym->num_verdef)) {
+				(void) fprintf(stderr,
+				    MSG_INTL(MSG_WARN_GNUVER), state->file,
+				    state->secname, EC_WORD(symndx),
+				    EC_HALF(verndx & ~0x8000));
+			} else {	/* Generic version range error */
+				(void) fprintf(stderr,
+				    MSG_INTL(MSG_ERR_BADVER), state->file,
+				    state->secname, EC_WORD(symndx),
+				    EC_HALF(verndx), state->versym->num_verdef);
+			}
+		}
+	} else {
 		verndx = 0;
+	}
 
 	/*
 	 * Error checking for TLS.
@@ -1345,7 +1424,7 @@
  */
 void
 symbols(Cache *cache, Word shnum, Ehdr *ehdr, const char *name,
-    Cache *versymcache, const char *file, uint_t flags)
+    VERSYM_STATE *versym, const char *file, uint_t flags)
 {
 	SYMTBL_STATE state;
 	Cache *_cache;
@@ -1366,7 +1445,7 @@
 			continue;
 
 		if (!init_symtbl_state(&state, cache, shnum, secndx, ehdr,
-		    versymcache, file, flags))
+		    versym, file, flags))
 			continue;
 		/*
 		 * Loop through the symbol tables entries.
@@ -1387,7 +1466,7 @@
  */
 static void
 sunw_sort(Cache *cache, Word shnum, Ehdr *ehdr, const char *name,
-    Cache *versymcache, const char *file, uint_t flags)
+    VERSYM_STATE *versym, const char *file, uint_t flags)
 {
 	SYMTBL_STATE	ldynsym_state,	dynsym_state;
 	Cache		*sortcache,	*symcache;
@@ -1429,7 +1508,7 @@
 		switch (symshdr->sh_type) {
 		case SHT_SUNW_LDYNSYM:
 			if (!init_symtbl_state(&ldynsym_state, cache, shnum,
-			    symsecndx, ehdr, versymcache, file, flags))
+			    symsecndx, ehdr, versym, file, flags))
 				continue;
 			ldynsym_cnt = ldynsym_state.symn;
 			/*
@@ -1455,7 +1534,7 @@
 			/*FALLTHROUGH*/
 		case SHT_DYNSYM:
 			if (!init_symtbl_state(&dynsym_state, cache, shnum,
-			    symsecndx, ehdr, versymcache, file, flags))
+			    symsecndx, ehdr, versym, file, flags))
 				continue;
 			break;
 		default:
@@ -2574,7 +2653,7 @@
 	Shdr		*nameshdr, *shdr;
 	char		*names = 0;
 	Cache		*cache, *_cache;
-	Cache		*versymcache = 0;
+	VERSYM_STATE	versym;
 
 	if ((ehdr = elf_getehdr(elf)) == NULL) {
 		failure(file, MSG_ORIG(MSG_ELF_GETEHDR));
@@ -2848,13 +2927,13 @@
 	if (flags & FLG_INTERP)
 		interp(file, cache, shnum, phnum, elf);
 
-	versymcache = versions(cache, shnum, file, flags);
+	versions(cache, shnum, file, flags, &versym);
 
 	if (flags & FLG_SYMBOLS)
-		symbols(cache, shnum, ehdr, Nname, versymcache, file, flags);
+		symbols(cache, shnum, ehdr, Nname, &versym, file, flags);
 
 	if (flags & FLG_SORT)
-		sunw_sort(cache, shnum, ehdr, Nname, versymcache, file, flags);
+		sunw_sort(cache, shnum, ehdr, Nname, &versym, file, flags);
 
 	if (flags & FLG_HASH)
 		hash(cache, shnum, Nname, file, flags);
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.msg	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.msg	Wed Mar 21 10:53:55 2007 -0700
@@ -106,8 +106,11 @@
 @ MSG_ERR_BADHASH	"%s: %s: bad hash entry: symbol %s: exists in bucket \
 			 %d, should be bucket %ld\n"
 @ MSG_ERR_NODYNSYM	"%s: %s: associated SHT_DYNSYM section not found\n"
-@ MSG_ERR_BADNDXSEC	"%s: %s: unexpected section type associated with index section: %s\n"
+@ MSG_ERR_BADNDXSEC	"%s: %s: unexpected section type associated with \
+			 index section: %s\n"
 @ MSG_ERR_BADSORTNDX	"%s: %s: sort section has bad symbol index: %d\n"
+@ MSG_ERR_BADVER	"%s: %s: index[%d]: version %d is out of range: \
+			 version definitions available: 0-%d\n"
 
 @ MSG_ERR_LDYNNOTADJ	"%s: bad dynamic symbol table layout: %s and %s \
 			 sections are not adjacent\n"
@@ -124,6 +127,7 @@
 			 header\n"
 @ MSG_WARN_INVCAP3	"%s: capabilities section: %s: and PT_CAP program \
 			 header have conflicting size or offsets\n"
+@ MSG_WARN_GNUVER	"%s: %s: index[%d]: GNU hidden symbol with version %d\n"
 
 # Elf Output Messages
 
@@ -246,6 +250,8 @@
 
 @ MSG_STR_EMPTY		""
 
+@ MSG_GNU_VERNAMPREFIX	".gnu.version"
+
 @ MSG_FMT_INDENT	"	%s"
 @ MSG_FMT_INDEX		" [%lld]"
 @ MSG_FMT_INDEX2	"[%d]"
--- a/usr/src/cmd/sgs/include/conv.h	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/include/conv.h	Wed Mar 21 10:53:55 2007 -0700
@@ -173,6 +173,7 @@
 extern	int		conv_sys_eclass();
 extern	Uts_desc	*conv_uts(void);
 extern	const char	*conv_ver_flags(Half);
+extern	const char	*conv_ver_index(Versym);
 
 /*
  * Define all class specific routines.
--- a/usr/src/cmd/sgs/include/debug.h	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/include/debug.h	Wed Mar 21 10:53:55 2007 -0700
@@ -335,6 +335,7 @@
 #define	Dbg_syms_entry		Dbg64_syms_entry
 #define	Dbg_syms_global		Dbg64_syms_global
 #define	Dbg_syms_ignore		Dbg64_syms_ignore
+#define	Dbg_syms_ignore_badver	Dbg64_syms_ignore_badver
 #define	Dbg_syms_lazy_rescan	Dbg64_syms_lazy_rescan
 #define	Dbg_syms_lookup		Dbg64_syms_lookup
 #define	Dbg_syms_new		Dbg64_syms_new
@@ -532,6 +533,7 @@
 #define	Dbg_syms_entry		Dbg32_syms_entry
 #define	Dbg_syms_global		Dbg32_syms_global
 #define	Dbg_syms_ignore		Dbg32_syms_ignore
+#define	Dbg_syms_ignore_badver	Dbg32_syms_ignore_badver
 #define	Dbg_syms_lazy_rescan	Dbg32_syms_lazy_rescan
 #define	Dbg_syms_lookup		Dbg32_syms_lookup
 #define	Dbg_syms_lookup_aout	Dbg32_syms_lookup_aout
@@ -767,6 +769,7 @@
 extern	void	Dbg_syms_entry(Lm_list *, Word, Sym_desc *);
 extern	void	Dbg_syms_global(Lm_list *, Word, const char *);
 extern	void	Dbg_syms_ignore(Ofl_desc *, Sym_desc *);
+extern	void	Dbg_syms_ignore_badver(Rt_map *, const char *, Word, Versym);
 extern	void	Dbg_syms_lazy_rescan(Lm_list *, const char *);
 extern	void	Dbg_syms_lookup(Rt_map *, const char *, const char *);
 #if	!(defined(_ELF64))
@@ -945,7 +948,7 @@
 extern	void	Elf_shdr(Lm_list *, Half, Shdr *);
 
 extern	void	Elf_syms_table_entry(Lm_list *, int, const char *, Half, Sym *,
-		    Word, const char *, const char *);
+		    Versym, const char *, const char *);
 extern	void	Elf_syms_table_title(Lm_list *, int);
 
 extern	void	Elf_ver_def_title(Lm_list *);
--- a/usr/src/cmd/sgs/include/libld.h	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/include/libld.h	Wed Mar 21 10:53:55 2007 -0700
@@ -933,6 +933,58 @@
 
 
 /*
+ * Test to see if a symbol verson index is outside of the valid range
+ * of version indexes.
+ *
+ * entry:
+ *	_shndx - Symbol section index
+ *	_vercnt - # of versions defined by object containing symbol
+ *	_versym_arr - NULL, or pointer to versym array
+ *	_verndx - Version index of symbol. Note that this argument is
+ *		only evaluated if _versym_arr is non-NULL.
+ *
+ * note:
+ *	_vercnt and _verndx are evaluated more than once. Beware
+ *	of expensive computations, or computations with side effects.
+ *
+ * If we encounter a defined symbol with a version that is outside the
+ * range of the valid versions supplied by the file, then we quietly
+ * ignore that symbol. This can't  happen in a native Solaris object.
+ * However, the GNU 'ld' uses the top bit (0x8000) of the version as a
+ * flag to the system that says the symbol should be treated as if it
+ * doesn't exist. The Solaris linker does not support this mechanism,
+ * or the model of interface evolution that it allows. However, we do
+ * wish to be able to link against objects produced that way. Ignoring
+ * such symbols gives the desired GNU-compatible "ignore" behavior,
+ * without committing us to their model, while reserving the ability
+ * to adopt it or do something different at a later date.
+ *
+ * Note that it is possible to see "version 1" in a file that contains 0
+ * version definitions. This happens when a mapfile is used to reduce
+ * global symbols to local. For instance:
+ *
+ *	{
+ *		global:
+ *			main;
+ *			eprintf;
+ *		local:
+ *			*;
+ *	};
+ *
+ * In this case, there will be a versym section (containing version
+ * indexes 0 and 1). However, there are no versions defined, and
+ * hence no corresponding verdef section. We treat this case specially:
+ * If the versym section is present (_versym_arr is non-NULL)
+ * and the verdef section is not, we act as if _vercnt is 1.
+ */
+#define	VERNDX_INVALID(_shndx, _vercnt, _versym_arr, _verndx) \
+	(((_shndx) != SHN_UNDEF) && (_versym_arr != NULL) && \
+	((_verndx) > ((_vercnt == 0) ? 1 : _vercnt)) && \
+	((_verndx) < VER_NDX_LORESERVE))
+
+
+
+/*
  * isalist(1) descriptor - used to break an isalist string into its component
  * options.
  */
--- a/usr/src/cmd/sgs/libconv/common/llib-lconv	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/llib-lconv	Wed Mar 21 10:53:55 2007 -0700
@@ -58,6 +58,7 @@
 int		conv_sys_eclass(void);
 Uts_desc	*conv_uts(void);
 const char	*conv_ver_flags(Half);
+const char	*conv_ver_index(Versym verndx);
 
 /*
  * Define all class specific routines.
--- a/usr/src/cmd/sgs/libconv/common/symbols.c	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/symbols.c	Wed Mar 21 10:53:55 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -133,6 +133,7 @@
 	    (mach == EM_SPARCV9)) && (type == STT_SPARC_REGISTER))
 		return (conv_sym_SPARC_value(value, 0));
 
-	(void) sprintf(string, MSG_ORIG(MSG_SYM_FMT_VAL), EC_ADDR(value));
+	(void) snprintf(string, sizeof (string), MSG_ORIG(MSG_SYM_FMT_VAL),
+	    EC_ADDR(value));
 	return (string);
 }
--- a/usr/src/cmd/sgs/libconv/common/version.c	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/version.c	Wed Mar 21 10:53:55 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -42,3 +42,22 @@
 	else
 		return (MSG_ORIG(MSG_GBL_NULL));
 }
+
+
+/*
+ * Format a version index as contained in a VERSYM section
+ */
+const char *
+conv_ver_index(Versym verndx)
+{
+	static Conv_inv_buf_t	string;
+
+	/* Special case versions starting at VER_NDX_LORESERVE */
+	if (verndx == VER_NDX_ELIMINATE)
+		return (MSG_ORIG(MSG_VERSYM_ELIMINATE));
+
+	/* format as numeric */
+	(void) snprintf(string, sizeof (string), MSG_ORIG(MSG_VERSYM_FMT),
+	    EC_HALF(verndx));
+	return (string);
+}
--- a/usr/src/cmd/sgs/libconv/common/version.msg	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/version.msg	Wed Mar 21 10:53:55 2007 -0700
@@ -1,13 +1,12 @@
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -29,4 +28,8 @@
 @ MSG_VER_FLG_WEAK	"[ WEAK ]"
 @ MSG_VER_FLG_BASE	"[ BASE ]"
 
+@ MSG_VERSYM_ELIMINATE	"ELIM"
+
 @ MSG_GBL_NULL		""
+
+@ MSG_VERSYM_FMT	"%d"
--- a/usr/src/cmd/sgs/libld/common/syms.c	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/libld/common/syms.c	Wed Mar 21 10:53:55 2007 -0700
@@ -1144,7 +1144,7 @@
 
 		if (undef) {
 			/*
-			 * If an non-weak reference remains undefined, or if a
+			 * If a non-weak reference remains undefined, or if a
 			 * mapfile reference is not bound to the relocatable
 			 * objects that make up the object being built, we have
 			 * a fatal error.
@@ -2005,6 +2005,17 @@
 		}
 
 		/*
+		 * To accomodate objects built with the GNU ld, we quietly
+		 * ignore symbols with a version that is outside the range
+		 * of the valid versions supplied by the file. See the
+		 * comment that accompanies the VERSYM_INVALID macro in libld.h
+		 * for additional details.
+		 */
+		if (VERNDX_INVALID(shndx, ifl->ifl_vercnt, ifl->ifl_versym,
+		    ifl->ifl_versym[ndx]))
+			continue;
+
+		/*
 		 * The linker itself will generate symbols for _end, _etext,
 		 * _edata, _DYNAMIC and _PROCEDURE_LINKAGE_TABLE_, so don't
 		 * bother entering these symbols from shared objects.  This
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Wed Mar 21 10:53:55 2007 -0700
@@ -643,6 +643,9 @@
 @ MSG_SYM_DUPSORTADDR	"section %s: symbol `%s' and symbol `%s' have the \
 			 same address: %#llx"
 
+@ MSG_SYM_IGNBADVER	"symbol=%s;  hash index=%d;  version=%d;  skipping \
+			 symbol with out of range version in file=%s"
+
 # Syminfo string
 
 @ MSG_SYMINFO_INFO	"syminfo information"
@@ -820,7 +823,7 @@
 			 oth ver shndx          name"
 @ MSG_SYM_LDS_TITLE_32	"              value      size      type bind \
 			 oth ver shndx"
-@ MSG_SYM_EFS_ENTRY_32	"%10.10s  %10.10s 0x%8.8x  %4s %4s %2s %4d \
+@ MSG_SYM_EFS_ENTRY_32	"%10.10s  %10.10s 0x%8.8x  %4s %4s %2s %4s \
 			 %-14.14s %s"
 
 # TRANSLATION_NOTE - the following entries provide for a series of one or more
@@ -830,7 +833,7 @@
 			 oth ver shndx / name"
 @ MSG_SYM_LDL_TITLE_32	"              value      size      type bind \
 			 oth ver shndx"
-@ MSG_SYM_EFL_ENTRY_32	"%10.10s  %10.10s 0x%8.8x  %4s %4s %2s %4d \
+@ MSG_SYM_EFL_ENTRY_32	"%10.10s  %10.10s 0x%8.8x  %4s %4s %2s %4s \
 			 %-14s %s"
 
 # TRANSLATION_NOTE - the following entries provide for a series of one or more
@@ -840,7 +843,7 @@
 			 type bind oth ver shndx          name"
 @ MSG_SYM_LDS_TITLE_64	"              value              size              \
 			 type bind oth ver shndx"
-@ MSG_SYM_EFS_ENTRY_64	"%10.10s  %18.18s 0x%16.16llx  %4s %4s %2s %4d \
+@ MSG_SYM_EFS_ENTRY_64	"%10.10s  %18.18s 0x%16.16llx  %4s %4s %2s %4s \
 			 %-14.14s %s"
 
 # TRANSLATION_NOTE - the following entries provide for a series of one or more
@@ -850,7 +853,7 @@
 			 type bind oth ver shndx / name"
 @ MSG_SYM_LDL_TITLE_64	"              value              size              \
 			 type bind oth ver shndx"
-@ MSG_SYM_EFL_ENTRY_64	"%10.10s  %18.18s 0x%16.16llx  %4s %4s %2s %4d \
+@ MSG_SYM_EFL_ENTRY_64	"%10.10s  %18.18s 0x%16.16llx  %4s %4s %2s %4s \
 			 %-14s %s"
 
 
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Wed Mar 21 10:53:55 2007 -0700
@@ -490,8 +490,8 @@
 void Elf32_shdr(Lm_list *, Elf32_Half, Elf32_Shdr *);
 
 void Elf64_syms_table_entry(Lm_list *, int, const char *, Elf64_Half,
-    Elf64_Sym *, Elf64_Word, const char *, const char *);
+    Elf64_Sym *, Elf64_Versym, const char *, const char *);
 void Elf32_syms_table_entry(Lm_list *, int, const char *, Elf32_Half,
-    Elf32_Sym *, Elf32_Word, const char *, const char *);
+    Elf32_Sym *, Elf32_Versym, const char *, const char *);
 void Elf64_syms_table_title(Lm_list *, int);
 void Elf32_syms_table_title(Lm_list *, int);
--- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Wed Mar 21 10:53:55 2007 -0700
@@ -38,7 +38,7 @@
 #	Policy for Shared Library Version Names and Interface Definitions
 
 
-SUNWprivate_4.58 {
+SUNWprivate_4.59 {
 	global:
 		dbg_desc = NODIRECT;	# interposed - ld.so.1(1)
 		dbg_print = NODIRECT;	# interposed - ld(1) and ld.so.1(1)
@@ -332,6 +332,8 @@
 		Dbg64_syms_global;
 		Dbg32_syms_ignore;
 		Dbg64_syms_ignore;
+		Dbg32_syms_ignore_badver;
+		Dbg64_syms_ignore_badver;
 		Dbg32_syms_lazy_rescan;
 		Dbg64_syms_lazy_rescan;
 		Dbg32_syms_lookup;
--- a/usr/src/cmd/sgs/liblddbg/common/syms.c	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/syms.c	Wed Mar 21 10:53:55 2007 -0700
@@ -57,6 +57,19 @@
 }
 
 void
+Dbg_syms_ignore_badver(Rt_map *lmp, const char *name, Word symndx,
+    Versym verndx)
+{
+	Lm_list	*lml = LIST(lmp);
+
+	if (DBG_NOTCLASS(DBG_C_SYMBOLS))
+		return;
+
+	dbg_print(lml, MSG_INTL(MSG_SYM_IGNBADVER), Dbg_demangle_name(name),
+	    EC_WORD(symndx), EC_HALF(verndx), NAME(lmp));
+}
+
+void
 Dbg_syms_dlsym(Rt_map *clmp, const char *sym, const char *next, int flag)
 {
 	const char	*str, *from = NAME(clmp);
@@ -505,7 +518,7 @@
 
 void
 Elf_syms_table_entry(Lm_list *lml, int caller, const char *prestr, Half mach,
-    Sym *sym, Word verndx, const char *sec, const char *poststr)
+    Sym *sym, Versym verndx, const char *sec, const char *poststr)
 {
 	uchar_t		type = ELF_ST_TYPE(sym->st_info);
 	uchar_t		bind = ELF_ST_BIND(sym->st_info);
@@ -522,7 +535,8 @@
 		    conv_sym_value(mach, type, sym->st_value), sym->st_size,
 		    conv_sym_info_type(mach, type, 0),
 		    conv_sym_info_bind(bind, 0), conv_sym_other(sym->st_other),
-		    verndx, sec ? sec : conv_sym_shndx(sym->st_shndx),
+		    conv_ver_index(verndx),
+		    sec ? sec : conv_sym_shndx(sym->st_shndx),
 		    Elf_demangle_name(poststr));
 	}
 }
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README	Wed Mar 21 10:53:55 2007 -0700
@@ -1223,3 +1223,5 @@
 6516118 Reserved space needed in ELF dynamic section and string table (D)
 	PSARC/2007/127 Reserved space for editing ELF dynamic sections
 6535688 elfdump could be more robust in the face of Purify (D)
+6516665 The link-editors should be more resilient against gcc's symbol
+	versioning
--- a/usr/src/cmd/sgs/rtld/common/_elf.h	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/rtld/common/_elf.h	Wed Mar 21 10:53:55 2007 -0700
@@ -114,6 +114,7 @@
 	int		e_verneednum;	/*	their associated count */
 	Verdef		*e_verdef;	/* versions defined by this image and */
 	int		e_verdefnum;	/*	their associated count */
+	Versym 		*e_versym;	/* Per-symbol versions */
 	ulong_t		e_syminent;	/* syminfo entry size */
 	void		*e_pltpad;	/* PLTpad table */
 	void		*e_pltpadend;	/* end of PLTpad table */
@@ -147,6 +148,7 @@
 #define	VERNEEDNUM(X)		(((Rt_elfp *)(X)->rt_priv)->e_verneednum)
 #define	VERDEF(X)		(((Rt_elfp *)(X)->rt_priv)->e_verdef)
 #define	VERDEFNUM(X)		(((Rt_elfp *)(X)->rt_priv)->e_verdefnum)
+#define	VERSYM(X)		(((Rt_elfp *)(X)->rt_priv)->e_versym)
 #define	SUNWBSS(X)		(((Rt_elfp *)(X)->rt_priv)->e_sunwbss)
 #define	SYMINENT(X)		(((Rt_elfp *)(X)->rt_priv)->e_syminent)
 #define	PLTPAD(X)		(((Rt_elfp *)(X)->rt_priv)->e_pltpad)
--- a/usr/src/cmd/sgs/rtld/common/elf.c	Wed Mar 21 10:51:01 2007 -0700
+++ b/usr/src/cmd/sgs/rtld/common/elf.c	Wed Mar 21 10:53:55 2007 -0700
@@ -1846,6 +1846,22 @@
 		}
 
 		/*
+		 * To accomodate objects built with the GNU ld, we quietly
+		 * ignore symbols with a version that is outside the range
+		 * of the valid versions supplied by the file. See the
+		 * comment that accompanies the VERSYM_INVALID macro in libld.h
+		 * for additional details.
+		 */
+		if (VERNDX_INVALID(sym->st_shndx, VERDEFNUM(ilmp),
+		    VERSYM(ilmp), VERSYM(ilmp)[ndx])) {
+			DBG_CALL(Dbg_syms_ignore_badver(ilmp, name,
+			    ndx, VERSYM(ilmp)[ndx]));
+			if ((ndx = chainptr[ndx]) != 0)
+				continue;
+			return ((Sym *)0);
+		}
+
+		/*
 		 * If we're only here to establish a symbols index, we're done.
 		 */
 		if (slp->sl_flags & LKUP_SYMNDX)
@@ -2216,6 +2232,9 @@
 				/* LINTED */
 				VERDEFNUM(lmp) = (int)ld->d_un.d_val;
 				break;
+			case DT_VERSYM:
+				VERSYM(lmp) = (Versym *)(ld->d_un.d_ptr + base);
+				break;
 			case DT_BIND_NOW:
 				if ((ld->d_un.d_val & DF_BIND_NOW) &&
 				    ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) {