xref: /illumos-gate/usr/src/cmd/sgs/libld/common/version.c (revision 090a8d9e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215aefb655Srie 
227c478bd9Sstevel@tonic-gate /*
23*090a8d9eSAli Bahrami  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include	<string.h>
287c478bd9Sstevel@tonic-gate #include	<stdio.h>
295aefb655Srie #include	<debug.h>
307c478bd9Sstevel@tonic-gate #include	"msg.h"
317c478bd9Sstevel@tonic-gate #include	"_libld.h"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * Locate a version descriptor.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate Ver_desc *
385aefb655Srie ld_vers_find(const char *name, Word hash, List *lst)
397c478bd9Sstevel@tonic-gate {
407c478bd9Sstevel@tonic-gate 	Listnode	*lnp;
417c478bd9Sstevel@tonic-gate 	Ver_desc	*vdp;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(lst, lnp, vdp)) {
447c478bd9Sstevel@tonic-gate 		if (vdp->vd_hash != hash)
457c478bd9Sstevel@tonic-gate 			continue;
467c478bd9Sstevel@tonic-gate 		if (strcmp(vdp->vd_name, name) == 0)
477c478bd9Sstevel@tonic-gate 			return (vdp);
487c478bd9Sstevel@tonic-gate 	}
497c478bd9Sstevel@tonic-gate 	return (0);
507c478bd9Sstevel@tonic-gate }
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * Add a new version descriptor to a version descriptor list.  Note, users of
547c478bd9Sstevel@tonic-gate  * this are responsible for determining if the version descriptor already
557c478bd9Sstevel@tonic-gate  * exists (this can reduce the need to allocate storage for descriptor names
567c478bd9Sstevel@tonic-gate  * until it is determined a descriptor need be created (see map_symbol())).
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate Ver_desc *
595aefb655Srie ld_vers_desc(const char *name, Word hash, List *lst)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate 	Ver_desc	*vdp;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	if ((vdp = libld_calloc(sizeof (Ver_desc), 1)) == 0)
647c478bd9Sstevel@tonic-gate 		return ((Ver_desc *)S_ERROR);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	vdp->vd_name = name;
677c478bd9Sstevel@tonic-gate 	vdp->vd_hash = hash;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	if (list_appendc(lst, vdp) == 0)
707c478bd9Sstevel@tonic-gate 		return ((Ver_desc *)S_ERROR);
717c478bd9Sstevel@tonic-gate 	else
727c478bd9Sstevel@tonic-gate 		return (vdp);
737c478bd9Sstevel@tonic-gate }
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate  * Now that all explict files have been processed validate any version
777c478bd9Sstevel@tonic-gate  * definitions.  Insure that any version references are available (a version
787c478bd9Sstevel@tonic-gate  * has been defined when it's been assigned an index).  Also calculate the
797c478bd9Sstevel@tonic-gate  * number of .version section entries that will be required to hold this
807c478bd9Sstevel@tonic-gate  * information.
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate #define	_NUM_OF_VERS_	40	/* twice as big as the depth for libc version */
837c478bd9Sstevel@tonic-gate typedef struct {
847c478bd9Sstevel@tonic-gate 	Ver_desc	**ver_stk;
857c478bd9Sstevel@tonic-gate 	int 		ver_sp;
867c478bd9Sstevel@tonic-gate 	int 		ver_lmt;
877c478bd9Sstevel@tonic-gate } Ver_Stack;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate static uintptr_t
905aefb655Srie vers_visit_children(Ofl_desc *ofl, Ver_desc *vp, int flag)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	Listnode		*lnp1;
937c478bd9Sstevel@tonic-gate 	Ver_desc		*vdp;
947c478bd9Sstevel@tonic-gate 	static int		err = 0;
957c478bd9Sstevel@tonic-gate 	static Ver_Stack	ver_stk = {0, 0, 0};
967c478bd9Sstevel@tonic-gate 	int			tmp_sp;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	/*
997c478bd9Sstevel@tonic-gate 	 * If there was any fatal error,
1007c478bd9Sstevel@tonic-gate 	 * just return.
1017c478bd9Sstevel@tonic-gate 	 */
1027c478bd9Sstevel@tonic-gate 	if (err == S_ERROR)
1037c478bd9Sstevel@tonic-gate 		return (err);
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	/*
1067c478bd9Sstevel@tonic-gate 	 * if this is called from, ver_check_defs(), initialize sp.
1077c478bd9Sstevel@tonic-gate 	 */
1087c478bd9Sstevel@tonic-gate 	if (flag == 0)
1097c478bd9Sstevel@tonic-gate 		ver_stk.ver_sp = 0;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	/*
1127c478bd9Sstevel@tonic-gate 	 * Check if passed version pointer vp is already in the stack.
1137c478bd9Sstevel@tonic-gate 	 */
1147c478bd9Sstevel@tonic-gate 	for (tmp_sp = 0; tmp_sp < ver_stk.ver_sp; tmp_sp++) {
1157c478bd9Sstevel@tonic-gate 		Ver_desc *v;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 		v = ver_stk.ver_stk[tmp_sp];
1187c478bd9Sstevel@tonic-gate 		if (v == vp) {
1197c478bd9Sstevel@tonic-gate 			/*
1207c478bd9Sstevel@tonic-gate 			 * cyclic dependency.
1217c478bd9Sstevel@tonic-gate 			 */
1227c478bd9Sstevel@tonic-gate 			if (err == 0) {
1235aefb655Srie 				eprintf(ofl->ofl_lml, ERR_FATAL,
1245aefb655Srie 				    MSG_INTL(MSG_VER_CYCLIC));
1257c478bd9Sstevel@tonic-gate 				err = 1;
1267c478bd9Sstevel@tonic-gate 			}
1277c478bd9Sstevel@tonic-gate 			for (tmp_sp = 0; tmp_sp < ver_stk.ver_sp; tmp_sp++) {
1287c478bd9Sstevel@tonic-gate 				v = ver_stk.ver_stk[tmp_sp];
1297c478bd9Sstevel@tonic-gate 				if ((v->vd_flags & FLG_VER_CYCLIC) == 0) {
1307c478bd9Sstevel@tonic-gate 					v->vd_flags |= FLG_VER_CYCLIC;
1315aefb655Srie 					eprintf(ofl->ofl_lml, ERR_NONE,
1325aefb655Srie 					    MSG_INTL(MSG_VER_ADDVER),
1335aefb655Srie 					    v->vd_name);
1347c478bd9Sstevel@tonic-gate 				}
1357c478bd9Sstevel@tonic-gate 			}
1367c478bd9Sstevel@tonic-gate 			if ((vp->vd_flags & FLG_VER_CYCLIC) == 0) {
1377c478bd9Sstevel@tonic-gate 				vp->vd_flags |= FLG_VER_CYCLIC;
1385aefb655Srie 				eprintf(ofl->ofl_lml, ERR_NONE,
1395aefb655Srie 				    MSG_INTL(MSG_VER_ADDVER), vp->vd_name);
1407c478bd9Sstevel@tonic-gate 			}
1417c478bd9Sstevel@tonic-gate 			return (err);
1427c478bd9Sstevel@tonic-gate 		}
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	/*
1467c478bd9Sstevel@tonic-gate 	 * Push version on the stack.
1477c478bd9Sstevel@tonic-gate 	 */
1487c478bd9Sstevel@tonic-gate 	if (ver_stk.ver_sp >= ver_stk.ver_lmt) {
1497c478bd9Sstevel@tonic-gate 		ver_stk.ver_lmt += _NUM_OF_VERS_;
1507c478bd9Sstevel@tonic-gate 		if ((ver_stk.ver_stk = (Ver_desc **)
1517c478bd9Sstevel@tonic-gate 		    libld_realloc((void *)ver_stk.ver_stk,
1527c478bd9Sstevel@tonic-gate 		    ver_stk.ver_lmt * sizeof (Ver_desc *))) == NULL)
1537c478bd9Sstevel@tonic-gate 			return (S_ERROR);
1547c478bd9Sstevel@tonic-gate 	}
1557c478bd9Sstevel@tonic-gate 	ver_stk.ver_stk[(ver_stk.ver_sp)++] = vp;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	/*
1587c478bd9Sstevel@tonic-gate 	 * Now visit children.
1597c478bd9Sstevel@tonic-gate 	 */
1607c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&vp->vd_deps, lnp1, vdp))
1615aefb655Srie 		if (vers_visit_children(ofl, vdp, 1) == S_ERROR)
1627c478bd9Sstevel@tonic-gate 			return (S_ERROR);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	/*
1657c478bd9Sstevel@tonic-gate 	 * Pop version from the stack.
1667c478bd9Sstevel@tonic-gate 	 */
1677c478bd9Sstevel@tonic-gate 	(ver_stk.ver_sp)--;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	return (err);
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate uintptr_t
1735aefb655Srie ld_vers_check_defs(Ofl_desc *ofl)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate 	Listnode	*lnp1, *lnp2;
1767c478bd9Sstevel@tonic-gate 	Ver_desc	*vdp;
1777c478bd9Sstevel@tonic-gate 	uintptr_t 	is_cyclic = 0;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 
1805aefb655Srie 	DBG_CALL(Dbg_ver_def_title(ofl->ofl_lml, ofl->ofl_name));
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/*
1837c478bd9Sstevel@tonic-gate 	 * First check if there are any cyclic dependency
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ofl->ofl_verdesc, lnp1, vdp))
1865aefb655Srie 		if ((is_cyclic = vers_visit_children(ofl, vdp, 0)) == S_ERROR)
1877c478bd9Sstevel@tonic-gate 			return (S_ERROR);
1887c478bd9Sstevel@tonic-gate 	if (is_cyclic)
1897c478bd9Sstevel@tonic-gate 		ofl->ofl_flags |= FLG_OF_FATAL;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ofl->ofl_verdesc, lnp1, vdp)) {
1927c478bd9Sstevel@tonic-gate 		Byte		cnt;
1937c478bd9Sstevel@tonic-gate 		Sym		*sym;
1947c478bd9Sstevel@tonic-gate 		Sym_desc	*sdp;
1957c478bd9Sstevel@tonic-gate 		const char	*name = vdp->vd_name;
1967c478bd9Sstevel@tonic-gate 		unsigned char	bind;
1977c478bd9Sstevel@tonic-gate 		Ver_desc	*_vdp;
1987c478bd9Sstevel@tonic-gate 		avl_index_t	where;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 		if (vdp->vd_ndx == 0) {
2015aefb655Srie 			eprintf(ofl->ofl_lml, ERR_FATAL,
2025aefb655Srie 			    MSG_INTL(MSG_VER_UNDEF), name, vdp->vd_ref->vd_name,
2037c478bd9Sstevel@tonic-gate 			    vdp->vd_ref->vd_file->ifl_name);
2047c478bd9Sstevel@tonic-gate 			ofl->ofl_flags |= FLG_OF_FATAL;
2057c478bd9Sstevel@tonic-gate 			continue;
2067c478bd9Sstevel@tonic-gate 		}
2077c478bd9Sstevel@tonic-gate 
2085aefb655Srie 		DBG_CALL(Dbg_ver_desc_entry(ofl->ofl_lml, vdp));
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 		/*
2117c478bd9Sstevel@tonic-gate 		 * If a version definition contains no symbols this is possibly
2127c478bd9Sstevel@tonic-gate 		 * a mapfile error.
2137c478bd9Sstevel@tonic-gate 		 */
2147c478bd9Sstevel@tonic-gate 		if ((vdp->vd_flags &
2157c478bd9Sstevel@tonic-gate 		    (VER_FLG_BASE | VER_FLG_WEAK | FLG_VER_REFER)) == 0)
2165aefb655Srie 			DBG_CALL(Dbg_ver_nointerface(ofl->ofl_lml,
2175aefb655Srie 			    vdp->vd_name));
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		/*
2207c478bd9Sstevel@tonic-gate 		 * Update the version entry count to account for this new
2217c478bd9Sstevel@tonic-gate 		 * version descriptor (the count is the size in bytes).
2227c478bd9Sstevel@tonic-gate 		 */
2237c478bd9Sstevel@tonic-gate 		ofl->ofl_verdefsz += sizeof (Verdef);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 		/*
2267c478bd9Sstevel@tonic-gate 		 * Traverse this versions dependency list to determine what
2277c478bd9Sstevel@tonic-gate 		 * additional version dependencies we must account for against
2287c478bd9Sstevel@tonic-gate 		 * this descriptor.
2297c478bd9Sstevel@tonic-gate 		 */
2307c478bd9Sstevel@tonic-gate 		cnt = 1;
2317c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&vdp->vd_deps, lnp2, _vdp)) {
2327c478bd9Sstevel@tonic-gate #if	defined(__lint)
2337c478bd9Sstevel@tonic-gate 			/* get lint to think `_vdp' is used... */
2347c478bd9Sstevel@tonic-gate 			lnp2 = (Listnode *)_vdp;
2357c478bd9Sstevel@tonic-gate #endif
2367c478bd9Sstevel@tonic-gate 			cnt++;
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 		ofl->ofl_verdefsz += (cnt * sizeof (Verdaux));
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 		/*
2417c478bd9Sstevel@tonic-gate 		 * Except for the base version descriptor, generate an absolute
2427c478bd9Sstevel@tonic-gate 		 * symbol to reflect this version.
2437c478bd9Sstevel@tonic-gate 		 */
2447c478bd9Sstevel@tonic-gate 		if (vdp->vd_flags & VER_FLG_BASE)
2457c478bd9Sstevel@tonic-gate 			continue;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 		if (vdp->vd_flags & VER_FLG_WEAK)
2487c478bd9Sstevel@tonic-gate 			bind = STB_WEAK;
2497c478bd9Sstevel@tonic-gate 		else
2507c478bd9Sstevel@tonic-gate 			bind = STB_GLOBAL;
2517c478bd9Sstevel@tonic-gate 
2525aefb655Srie 		if (sdp = ld_sym_find(name, vdp->vd_hash, &where, ofl)) {
2537c478bd9Sstevel@tonic-gate 			/*
2547c478bd9Sstevel@tonic-gate 			 * If the symbol already exists and is undefined or was
2557c478bd9Sstevel@tonic-gate 			 * defined in a shared library, convert it to an
2567c478bd9Sstevel@tonic-gate 			 * absolute.
2577c478bd9Sstevel@tonic-gate 			 */
2580bc07c75Srie 			if ((sdp->sd_sym->st_shndx == SHN_UNDEF) ||
2597c478bd9Sstevel@tonic-gate 			    (sdp->sd_ref != REF_REL_NEED)) {
2607c478bd9Sstevel@tonic-gate 				sdp->sd_shndx = sdp->sd_sym->st_shndx = SHN_ABS;
2617c478bd9Sstevel@tonic-gate 				sdp->sd_sym->st_info =
26260758829Srie 				    ELF_ST_INFO(bind, STT_OBJECT);
2637c478bd9Sstevel@tonic-gate 				sdp->sd_ref = REF_REL_NEED;
2647c478bd9Sstevel@tonic-gate 				sdp->sd_flags |= FLG_SY_SPECSEC;
26560758829Srie 				sdp->sd_flags1 |=
26660758829Srie 				    (FLG_SY1_DEFAULT | FLG_SY1_EXPDEF);
2677c478bd9Sstevel@tonic-gate 				sdp->sd_aux->sa_overndx = vdp->vd_ndx;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 				/*
2707c478bd9Sstevel@tonic-gate 				 * If the reference originated from a mapfile
2717c478bd9Sstevel@tonic-gate 				 * insure we mark the symbol as used.
2727c478bd9Sstevel@tonic-gate 				 */
2737c478bd9Sstevel@tonic-gate 				if (sdp->sd_flags & FLG_SY_MAPREF)
2747c478bd9Sstevel@tonic-gate 					sdp->sd_flags |= FLG_SY_MAPUSED;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 			} else if ((sdp->sd_flags & FLG_SY_SPECSEC) &&
2770bc07c75Srie 			    (sdp->sd_sym->st_shndx != SHN_ABS) &&
2787c478bd9Sstevel@tonic-gate 			    (sdp->sd_ref == REF_REL_NEED)) {
2795aefb655Srie 				eprintf(ofl->ofl_lml, ERR_WARNING,
2805aefb655Srie 				    MSG_INTL(MSG_VER_DEFINED), name,
2815aefb655Srie 				    sdp->sd_file->ifl_name);
2827c478bd9Sstevel@tonic-gate 			}
2837c478bd9Sstevel@tonic-gate 		} else {
2847c478bd9Sstevel@tonic-gate 			/*
2857c478bd9Sstevel@tonic-gate 			 * If the symbol does not exist create it.
2867c478bd9Sstevel@tonic-gate 			 */
2877c478bd9Sstevel@tonic-gate 			if ((sym = libld_calloc(sizeof (Sym), 1)) == 0)
2887c478bd9Sstevel@tonic-gate 				return (S_ERROR);
2897c478bd9Sstevel@tonic-gate 			sym->st_shndx = SHN_ABS;
2907c478bd9Sstevel@tonic-gate 			sym->st_info = ELF_ST_INFO(bind, STT_OBJECT);
2915aefb655Srie 			DBG_CALL(Dbg_ver_symbol(ofl->ofl_lml, name));
2925aefb655Srie 			if ((sdp = ld_sym_enter(name, sym, vdp->vd_hash,
2937c478bd9Sstevel@tonic-gate 			    vdp->vd_file, ofl, 0, SHN_ABS, FLG_SY_SPECSEC,
29460758829Srie 			    (FLG_SY1_DEFAULT | FLG_SY1_EXPDEF),
29560758829Srie 			    &where)) == (Sym_desc *)S_ERROR)
2967c478bd9Sstevel@tonic-gate 				return (S_ERROR);
2977c478bd9Sstevel@tonic-gate 			sdp->sd_ref = REF_REL_NEED;
2987c478bd9Sstevel@tonic-gate 			sdp->sd_aux->sa_overndx = vdp->vd_ndx;
2997c478bd9Sstevel@tonic-gate 		}
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 	return (1);
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate  * Dereference dependencies as a part of normalizing (allows recursion).
3067c478bd9Sstevel@tonic-gate  */
3075aefb655Srie static void
3087c478bd9Sstevel@tonic-gate vers_derefer(Ifl_desc *ifl, Ver_desc *vdp, int weak)
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 	Listnode	*lnp;
3117c478bd9Sstevel@tonic-gate 	Ver_desc	*_vdp;
3127c478bd9Sstevel@tonic-gate 	Ver_index	*vip = &ifl->ifl_verndx[vdp->vd_ndx];
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/*
315*090a8d9eSAli Bahrami 	 * Set the INFO bit on all dependencies that ld.so.1
316*090a8d9eSAli Bahrami 	 * can skip verification for. These are the dependencies
317*090a8d9eSAli Bahrami 	 * that are inherited by others -- verifying the inheriting
318*090a8d9eSAli Bahrami 	 * version implicitily covers this one.
319*090a8d9eSAli Bahrami 	 *
320*090a8d9eSAli Bahrami 	 * If the head of the list was a weak then we only mark
3217c478bd9Sstevel@tonic-gate 	 * weak dependencies, but if the head of the list was 'strong'
322*090a8d9eSAli Bahrami 	 * we set INFO on all dependencies.
3237c478bd9Sstevel@tonic-gate 	 */
3247c478bd9Sstevel@tonic-gate 	if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak))
325*090a8d9eSAli Bahrami 		vip->vi_flags |= VER_FLG_INFO;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&vdp->vd_deps, lnp, _vdp))
3287c478bd9Sstevel@tonic-gate 		vers_derefer(ifl, _vdp, weak);
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate /*
3327c478bd9Sstevel@tonic-gate  * If we need to record the versions of any needed dependencies traverse the
3337c478bd9Sstevel@tonic-gate  * shared object dependency list and calculate what version needed entries are
3347c478bd9Sstevel@tonic-gate  * required.
3357c478bd9Sstevel@tonic-gate  */
3367c478bd9Sstevel@tonic-gate uintptr_t
3375aefb655Srie ld_vers_check_need(Ofl_desc *ofl)
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate 	Listnode	*lnp1;
3407c478bd9Sstevel@tonic-gate 	Ifl_desc	*ifl;
341*090a8d9eSAli Bahrami 	Half		needndx;
342*090a8d9eSAli Bahrami 
343*090a8d9eSAli Bahrami 	/*
344*090a8d9eSAli Bahrami 	 * Versym indexes for needed versions start with the next
345*090a8d9eSAli Bahrami 	 * available version after the final definied version.
346*090a8d9eSAli Bahrami 	 * However, it can never be less than 2. 0 is always for local
347*090a8d9eSAli Bahrami 	 * scope, and 1 is always the first global definition.
348*090a8d9eSAli Bahrami 	 */
349*090a8d9eSAli Bahrami 	needndx = (ofl->ofl_vercnt > 0) ? (ofl->ofl_vercnt + 1) : 2;
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	/*
3527c478bd9Sstevel@tonic-gate 	 * Traverse the shared object list looking for dependencies.
3537c478bd9Sstevel@tonic-gate 	 */
3547c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ofl->ofl_sos, lnp1, ifl)) {
3557c478bd9Sstevel@tonic-gate 		Listnode	*lnp2;
3567c478bd9Sstevel@tonic-gate 		Ver_index	*vip;
3577c478bd9Sstevel@tonic-gate 		Ver_desc	*vdp;
3587c478bd9Sstevel@tonic-gate 		Sdf_desc	*sdf = ifl->ifl_sdfdesc;
359*090a8d9eSAli Bahrami 		Byte		cnt, need = 0;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 		if (!(ifl->ifl_flags & FLG_IF_NEEDED))
3627c478bd9Sstevel@tonic-gate 			continue;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 		if (ifl->ifl_vercnt <= VER_NDX_GLOBAL)
3657c478bd9Sstevel@tonic-gate 			continue;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 		/*
3687c478bd9Sstevel@tonic-gate 		 * If version needed definitions were specified in
369*090a8d9eSAli Bahrami 		 * a mapfile ($SPECVERS=) then record those definitions.
3707c478bd9Sstevel@tonic-gate 		 */
3717c478bd9Sstevel@tonic-gate 		if (sdf && (sdf->sdf_flags & FLG_SDF_SPECVER)) {
3727c478bd9Sstevel@tonic-gate 			Sdv_desc	*sdv;
3737c478bd9Sstevel@tonic-gate 			for (LIST_TRAVERSE(&sdf->sdf_verneed, lnp2,
3747c478bd9Sstevel@tonic-gate 			    sdv)) {
375*090a8d9eSAli Bahrami 
376*090a8d9eSAli Bahrami 				/*
377*090a8d9eSAli Bahrami 				 * If this $SPECVERS item corresponds to
378*090a8d9eSAli Bahrami 				 * a real version, then don't issue it
379*090a8d9eSAli Bahrami 				 * here, but use the real one instead.
380*090a8d9eSAli Bahrami 				 * This preserves the ability to reference it
381*090a8d9eSAli Bahrami 				 * from a symbol versym entry.
382*090a8d9eSAli Bahrami 				 */
383*090a8d9eSAli Bahrami 				if (sdv->sdv_flags & FLG_SDV_MATCHED)
384*090a8d9eSAli Bahrami 					continue;
385*090a8d9eSAli Bahrami 
386*090a8d9eSAli Bahrami 				/* Not found in known versions. Count it */
3877c478bd9Sstevel@tonic-gate 				ofl->ofl_verneedsz += sizeof (Vernaux);
3887c478bd9Sstevel@tonic-gate 				if (st_insert(ofl->ofl_dynstrtab,
3897c478bd9Sstevel@tonic-gate 				    sdv->sdv_name) == -1)
3907c478bd9Sstevel@tonic-gate 					return (S_ERROR);
391*090a8d9eSAli Bahrami 				need++;
3927c478bd9Sstevel@tonic-gate 			}
3937c478bd9Sstevel@tonic-gate 		}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 		/*
3967c478bd9Sstevel@tonic-gate 		 * Scan the version index list and if any weak version
3977c478bd9Sstevel@tonic-gate 		 * definition has been referenced by the user promote the
3987c478bd9Sstevel@tonic-gate 		 * dependency to be non-weak.  Weak version dependencies do not
3997c478bd9Sstevel@tonic-gate 		 * cause fatal errors from the runtime linker, non-weak
4007c478bd9Sstevel@tonic-gate 		 * dependencies do.
4017c478bd9Sstevel@tonic-gate 		 */
402*090a8d9eSAli Bahrami 		for (cnt = 0; cnt <= ifl->ifl_vercnt; cnt++) {
4037c478bd9Sstevel@tonic-gate 			vip = &ifl->ifl_verndx[cnt];
4047c478bd9Sstevel@tonic-gate 			vdp = vip->vi_desc;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 			if ((vip->vi_flags & (FLG_VER_REFER | VER_FLG_WEAK)) ==
4077c478bd9Sstevel@tonic-gate 			    (FLG_VER_REFER | VER_FLG_WEAK))
4087c478bd9Sstevel@tonic-gate 				vdp->vd_flags &= ~VER_FLG_WEAK;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 			/*
4117c478bd9Sstevel@tonic-gate 			 * Mark any weak reference as referred to so as to
4127c478bd9Sstevel@tonic-gate 			 * simplify normalization and later version dependency
4137c478bd9Sstevel@tonic-gate 			 * manipulation.
4147c478bd9Sstevel@tonic-gate 			 */
4157c478bd9Sstevel@tonic-gate 			if (vip->vi_flags & VER_FLG_WEAK)
4167c478bd9Sstevel@tonic-gate 				vip->vi_flags |= FLG_VER_REFER;
4177c478bd9Sstevel@tonic-gate 		}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 		/*
4207c478bd9Sstevel@tonic-gate 		 * Scan the version dependency list to normalize the referenced
4217c478bd9Sstevel@tonic-gate 		 * dependencies.  Any needed version that is inherited by
4227c478bd9Sstevel@tonic-gate 		 * another like version is derefereced as it is not necessary
4237c478bd9Sstevel@tonic-gate 		 * to make this part of the version dependencies.
4247c478bd9Sstevel@tonic-gate 		 */
4257c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&ifl->ifl_verdesc, lnp2, vdp)) {
4267c478bd9Sstevel@tonic-gate 			Listnode	*lnp3;
4277c478bd9Sstevel@tonic-gate 			Ver_desc	*_vdp;
4287c478bd9Sstevel@tonic-gate 			int		type;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 			vip = &ifl->ifl_verndx[vdp->vd_ndx];
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 			if (!(vip->vi_flags & FLG_VER_REFER))
4337c478bd9Sstevel@tonic-gate 				continue;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 			type = vdp->vd_flags & VER_FLG_WEAK;
4367c478bd9Sstevel@tonic-gate 			for (LIST_TRAVERSE(&vdp->vd_deps, lnp3, _vdp))
4377c478bd9Sstevel@tonic-gate 				vers_derefer(ifl, _vdp, type);
4387c478bd9Sstevel@tonic-gate 		}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 		/*
4417c478bd9Sstevel@tonic-gate 		 * Finally, determine how many of the version dependencies need
4427c478bd9Sstevel@tonic-gate 		 * to be recorded.
4437c478bd9Sstevel@tonic-gate 		 */
444*090a8d9eSAli Bahrami 		for (cnt = 0; cnt <= ifl->ifl_vercnt; cnt++) {
4457c478bd9Sstevel@tonic-gate 			vip = &ifl->ifl_verndx[cnt];
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 			/*
4487c478bd9Sstevel@tonic-gate 			 * If a version has been referenced then record it as a
4497c478bd9Sstevel@tonic-gate 			 * version dependency.
4507c478bd9Sstevel@tonic-gate 			 */
4517c478bd9Sstevel@tonic-gate 			if (vip->vi_flags & FLG_VER_REFER) {
452*090a8d9eSAli Bahrami 				/* Assign a VERSYM index for it */
453*090a8d9eSAli Bahrami 				vip->vi_overndx = needndx++;
454*090a8d9eSAli Bahrami 
4557c478bd9Sstevel@tonic-gate 				ofl->ofl_verneedsz += sizeof (Vernaux);
4567c478bd9Sstevel@tonic-gate 				if (st_insert(ofl->ofl_dynstrtab,
4577c478bd9Sstevel@tonic-gate 				    vip->vi_name) == -1)
4587c478bd9Sstevel@tonic-gate 					return (S_ERROR);
4597c478bd9Sstevel@tonic-gate 				need++;
4607c478bd9Sstevel@tonic-gate 			}
4617c478bd9Sstevel@tonic-gate 		}
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 		if (need) {
4647c478bd9Sstevel@tonic-gate 			ifl->ifl_flags |= FLG_IF_VERNEED;
4657c478bd9Sstevel@tonic-gate 			ofl->ofl_verneedsz += sizeof (Verneed);
4667c478bd9Sstevel@tonic-gate 			if (st_insert(ofl->ofl_dynstrtab,
4677c478bd9Sstevel@tonic-gate 			    ifl->ifl_soname) == -1)
4687c478bd9Sstevel@tonic-gate 				return (S_ERROR);
4697c478bd9Sstevel@tonic-gate 		}
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	/*
4737c478bd9Sstevel@tonic-gate 	 * If no version needed information is required unset the output file
4747c478bd9Sstevel@tonic-gate 	 * flag.
4757c478bd9Sstevel@tonic-gate 	 */
4767c478bd9Sstevel@tonic-gate 	if (ofl->ofl_verneedsz == 0)
4777c478bd9Sstevel@tonic-gate 		ofl->ofl_flags &= ~FLG_OF_VERNEED;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	return (1);
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate /*
4837c478bd9Sstevel@tonic-gate  * Indicate dependency selection (allows recursion).
4847c478bd9Sstevel@tonic-gate  */
4855aefb655Srie static void
4865aefb655Srie vers_select(Ofl_desc *ofl, Ifl_desc *ifl, Ver_desc *vdp, const char *ref)
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate 	Listnode	*lnp;
4897c478bd9Sstevel@tonic-gate 	Ver_desc	*_vdp;
4907c478bd9Sstevel@tonic-gate 	Ver_index	*vip = &ifl->ifl_verndx[vdp->vd_ndx];
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	vip->vi_flags |= FLG_VER_AVAIL;
4935aefb655Srie 	DBG_CALL(Dbg_ver_avail_entry(ofl->ofl_lml, vip, ref));
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&vdp->vd_deps, lnp, _vdp))
4965aefb655Srie 		vers_select(ofl, ifl, _vdp, ref);
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate 
4995aefb655Srie static Ver_index *
5005aefb655Srie vers_index(Ofl_desc *ofl, Ifl_desc *ifl, int avail)
5017c478bd9Sstevel@tonic-gate {
5027c478bd9Sstevel@tonic-gate 	Listnode	*lnp;
5037c478bd9Sstevel@tonic-gate 	Ver_desc	*vdp;
5047c478bd9Sstevel@tonic-gate 	Ver_index	*vip;
5057c478bd9Sstevel@tonic-gate 	Sdf_desc	*sdf = ifl->ifl_sdfdesc;
5067c478bd9Sstevel@tonic-gate 	Word		count = ifl->ifl_vercnt;
5077c478bd9Sstevel@tonic-gate 	Sdv_desc	*sdv;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	/*
5107c478bd9Sstevel@tonic-gate 	 * Allocate an index array large enough to hold all of the files
5117c478bd9Sstevel@tonic-gate 	 * version descriptors.
5127c478bd9Sstevel@tonic-gate 	 */
5137c478bd9Sstevel@tonic-gate 	if ((vip = libld_calloc(sizeof (Ver_index),
5147c478bd9Sstevel@tonic-gate 	    (count + 1))) == 0)
5157c478bd9Sstevel@tonic-gate 		return ((Ver_index *)S_ERROR);
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ifl->ifl_verdesc, lnp, vdp)) {
5187c478bd9Sstevel@tonic-gate 		int		ndx = vdp->vd_ndx;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 		vip[ndx].vi_name = vdp->vd_name;
5217c478bd9Sstevel@tonic-gate 		vip[ndx].vi_desc = vdp;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 		/*
5247c478bd9Sstevel@tonic-gate 		 * Any relocatable object versions, and the `base' version are
5257c478bd9Sstevel@tonic-gate 		 * always available.
5267c478bd9Sstevel@tonic-gate 		 */
5277c478bd9Sstevel@tonic-gate 		if (avail || (vdp->vd_flags & VER_FLG_BASE))
5287c478bd9Sstevel@tonic-gate 			vip[ndx].vi_flags |= FLG_VER_AVAIL;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 		/*
5317c478bd9Sstevel@tonic-gate 		 * If this is a weak version mark it as such.  Weak versions
5327c478bd9Sstevel@tonic-gate 		 * are always dragged into any version dependencies created,
5337c478bd9Sstevel@tonic-gate 		 * and if a weak version is referenced it will be promoted to
5347c478bd9Sstevel@tonic-gate 		 * a non-weak version dependency.
5357c478bd9Sstevel@tonic-gate 		 */
5367c478bd9Sstevel@tonic-gate 		if (vdp->vd_flags & VER_FLG_WEAK)
5377c478bd9Sstevel@tonic-gate 			vip[ndx].vi_flags |= VER_FLG_WEAK;
5387c478bd9Sstevel@tonic-gate 		/*
539*090a8d9eSAli Bahrami 		 * If this version is mentioned in a mapfile using
540*090a8d9eSAli Bahrami 		 * $ADDVERS or $SPECVERS syntax then check to see if
541*090a8d9eSAli Bahrami 		 * it corresponds to an actual version in the file.
5427c478bd9Sstevel@tonic-gate 		 */
543*090a8d9eSAli Bahrami 		if (sdf &&
544*090a8d9eSAli Bahrami 		    (sdf->sdf_flags & (FLG_SDF_SPECVER|FLG_SDF_ADDVER))) {
5457c478bd9Sstevel@tonic-gate 			Listnode *	lnp2;
5467c478bd9Sstevel@tonic-gate 			for (LIST_TRAVERSE(&sdf->sdf_verneed, lnp2, sdv)) {
5477c478bd9Sstevel@tonic-gate 				if (strcmp(vip[ndx].vi_name,
5487c478bd9Sstevel@tonic-gate 				    sdv->sdv_name) == 0) {
5497c478bd9Sstevel@tonic-gate 					vip[ndx].vi_flags |= FLG_VER_REFER;
550*090a8d9eSAli Bahrami 					if (sdf->sdf_flags & FLG_SDF_SPECVER)
551*090a8d9eSAli Bahrami 						vip[ndx].vi_flags |=
552*090a8d9eSAli Bahrami 						    FLG_VER_SPECVER;
5537c478bd9Sstevel@tonic-gate 					sdv->sdv_flags |= FLG_SDV_MATCHED;
5547c478bd9Sstevel@tonic-gate 					break;
5557c478bd9Sstevel@tonic-gate 				}
5567c478bd9Sstevel@tonic-gate 			}
5577c478bd9Sstevel@tonic-gate 		}
5587c478bd9Sstevel@tonic-gate 	}
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	/*
5617c478bd9Sstevel@tonic-gate 	 * if $ADDVER was specified for this object verify that
5627c478bd9Sstevel@tonic-gate 	 * all of it's dependent upon versions were refered to.
5637c478bd9Sstevel@tonic-gate 	 */
5647c478bd9Sstevel@tonic-gate 	if (sdf && (sdf->sdf_flags & FLG_SDF_ADDVER)) {
5657c478bd9Sstevel@tonic-gate 		int	fail = 0;
5667c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&sdf->sdf_verneed, lnp, sdv)) {
5677c478bd9Sstevel@tonic-gate 			if (!(sdv->sdv_flags & FLG_SDV_MATCHED)) {
5687c478bd9Sstevel@tonic-gate 				if (fail == 0) {
5697c478bd9Sstevel@tonic-gate 					fail++;
5705aefb655Srie 					eprintf(ofl->ofl_lml, ERR_NONE,
5717c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_VER_ADDVERS),
5727c478bd9Sstevel@tonic-gate 					    sdf->sdf_rfile, sdf->sdf_name);
5737c478bd9Sstevel@tonic-gate 				}
5745aefb655Srie 				eprintf(ofl->ofl_lml, ERR_NONE,
5755aefb655Srie 				    MSG_INTL(MSG_VER_ADDVER), sdv->sdv_name);
5767c478bd9Sstevel@tonic-gate 			}
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 		if (fail)
5797c478bd9Sstevel@tonic-gate 			return ((Ver_index *)S_ERROR);
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	return (vip);
5837c478bd9Sstevel@tonic-gate }
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate /*
5867c478bd9Sstevel@tonic-gate  * Process a version symbol index section.
5877c478bd9Sstevel@tonic-gate  */
5887c478bd9Sstevel@tonic-gate int
5895aefb655Srie ld_vers_sym_process(Lm_list *lml, Is_desc *isp, Ifl_desc *ifl)
5907c478bd9Sstevel@tonic-gate {
5917c478bd9Sstevel@tonic-gate 	Shdr	*symshdr;
5927c478bd9Sstevel@tonic-gate 	Shdr	*vershdr = isp->is_shdr;
5935aefb655Srie 
5947c478bd9Sstevel@tonic-gate 	/*
5955aefb655Srie 	 * Verify that the versym is the same size as the linked symbol table.
5965aefb655Srie 	 * If these two get out of sync the file is considered corrupted.
5977c478bd9Sstevel@tonic-gate 	 */
5987c478bd9Sstevel@tonic-gate 	symshdr = ifl->ifl_isdesc[vershdr->sh_link]->is_shdr;
5997c478bd9Sstevel@tonic-gate 	if ((symshdr->sh_size / symshdr->sh_entsize) != (vershdr->sh_size /
6007c478bd9Sstevel@tonic-gate 	    vershdr->sh_entsize)) {
6015aefb655Srie 		eprintf(lml, ERR_WARNING, MSG_INTL(MSG_ELF_VERSYM),
6025aefb655Srie 		    ifl->ifl_name, isp->is_name,
6035aefb655Srie 		    EC_WORD(vershdr->sh_size / vershdr->sh_entsize),
6045aefb655Srie 		    ifl->ifl_isdesc[vershdr->sh_link]->is_name,
6055aefb655Srie 		    EC_WORD(symshdr->sh_size / symshdr->sh_entsize));
6067c478bd9Sstevel@tonic-gate 		return (1);
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 	ifl->ifl_versym = (Versym *)isp->is_indata->d_buf;
6097c478bd9Sstevel@tonic-gate 	return (1);
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate /*
6137c478bd9Sstevel@tonic-gate  * Process a version definition section from an input file.  A list of version
6147c478bd9Sstevel@tonic-gate  * descriptors is created and associated with the input files descriptor.  If
6157c478bd9Sstevel@tonic-gate  * this is a shared object these descriptors will be used to indicate the
6167c478bd9Sstevel@tonic-gate  * availability of each version.  If this is a relocatable object then these
6177c478bd9Sstevel@tonic-gate  * descriptors will be promoted (concatenated) to the output files image.
6187c478bd9Sstevel@tonic-gate  */
6197c478bd9Sstevel@tonic-gate uintptr_t
6205aefb655Srie ld_vers_def_process(Is_desc *isp, Ifl_desc *ifl, Ofl_desc *ofl)
6217c478bd9Sstevel@tonic-gate {
6227c478bd9Sstevel@tonic-gate 	const char	*str, *file = ifl->ifl_name;
6237c478bd9Sstevel@tonic-gate 	Sdf_desc	*sdf = ifl->ifl_sdfdesc;
6247c478bd9Sstevel@tonic-gate 	Sdv_desc	*sdv;
6257c478bd9Sstevel@tonic-gate 	Word		num, _num;
6267c478bd9Sstevel@tonic-gate 	Verdef		*vdf;
6277c478bd9Sstevel@tonic-gate 	int		relobj;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	/*
6307c478bd9Sstevel@tonic-gate 	 * If there is no version section then simply indicate that all version
6317c478bd9Sstevel@tonic-gate 	 * definitions asked for do not exist.
6327c478bd9Sstevel@tonic-gate 	 */
6337c478bd9Sstevel@tonic-gate 	if (isp == 0) {
6347c478bd9Sstevel@tonic-gate 		Listnode	*lnp;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&sdf->sdf_vers, lnp, sdv)) {
6375aefb655Srie 			eprintf(ofl->ofl_lml, ERR_FATAL,
6385aefb655Srie 			    MSG_INTL(MSG_VER_NOEXIST), ifl->ifl_name,
6395aefb655Srie 			    sdv->sdv_name, sdv->sdv_ref);
6407c478bd9Sstevel@tonic-gate 			ofl->ofl_flags |= FLG_OF_FATAL;
6417c478bd9Sstevel@tonic-gate 		}
6427c478bd9Sstevel@tonic-gate 		return (0);
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	vdf = (Verdef *)isp->is_indata->d_buf;
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	/*
6487c478bd9Sstevel@tonic-gate 	 * Verify the version revision.  We only check the first version
6497c478bd9Sstevel@tonic-gate 	 * structure as it is assumed all other version structures in this
6507c478bd9Sstevel@tonic-gate 	 * data section will be of the same revision.
6517c478bd9Sstevel@tonic-gate 	 */
6527c478bd9Sstevel@tonic-gate 	if (vdf->vd_version > VER_DEF_CURRENT)
6535aefb655Srie 		(void) eprintf(ofl->ofl_lml, ERR_WARNING,
6545aefb655Srie 		    MSG_INTL(MSG_VER_HIGHER), ifl->ifl_name, vdf->vd_version,
6555aefb655Srie 		    VER_DEF_CURRENT);
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	num = isp->is_shdr->sh_info;
6597c478bd9Sstevel@tonic-gate 	str = (char *)ifl->ifl_isdesc[isp->is_shdr->sh_link]->is_indata->d_buf;
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	if (ifl->ifl_ehdr->e_type == ET_REL)
6627c478bd9Sstevel@tonic-gate 		relobj = 1;
6637c478bd9Sstevel@tonic-gate 	else
6647c478bd9Sstevel@tonic-gate 		relobj = 0;
6657c478bd9Sstevel@tonic-gate 
6665aefb655Srie 	DBG_CALL(Dbg_ver_def_title(ofl->ofl_lml, file));
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	/*
6697c478bd9Sstevel@tonic-gate 	 * Loop through the version information setting up a version descriptor
6707c478bd9Sstevel@tonic-gate 	 * for each version definition.
6717c478bd9Sstevel@tonic-gate 	 */
6727c478bd9Sstevel@tonic-gate 	for (_num = 1; _num <= num; _num++,
6737c478bd9Sstevel@tonic-gate 	    vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) {
6747c478bd9Sstevel@tonic-gate 		const char	*name;
6757c478bd9Sstevel@tonic-gate 		Ver_desc	*ivdp, *ovdp = 0;
6767c478bd9Sstevel@tonic-gate 		Word		hash;
6777c478bd9Sstevel@tonic-gate 		Half 		cnt = vdf->vd_cnt;
6787c478bd9Sstevel@tonic-gate 		Half		ndx = vdf->vd_ndx;
6797c478bd9Sstevel@tonic-gate 		Verdaux		*vdap = (Verdaux *)((uintptr_t)vdf +
68060758829Srie 		    vdf->vd_aux);
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 		/*
6837c478bd9Sstevel@tonic-gate 		 * Keep track of the largest index for use in creating a
6847c478bd9Sstevel@tonic-gate 		 * version index array later, and create a version descriptor.
6857c478bd9Sstevel@tonic-gate 		 */
6867c478bd9Sstevel@tonic-gate 		if (ndx > ifl->ifl_vercnt)
6877c478bd9Sstevel@tonic-gate 			ifl->ifl_vercnt = ndx;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 		name = (char *)(str + vdap->vda_name);
6907c478bd9Sstevel@tonic-gate 		/* LINTED */
6917c478bd9Sstevel@tonic-gate 		hash = (Word)elf_hash(name);
6925aefb655Srie 		if ((ivdp = ld_vers_find(name, hash, &ifl->ifl_verdesc)) == 0) {
6935aefb655Srie 			if ((ivdp = ld_vers_desc(name, hash,
6947c478bd9Sstevel@tonic-gate 			    &ifl->ifl_verdesc)) == (Ver_desc *)S_ERROR)
6957c478bd9Sstevel@tonic-gate 				return (S_ERROR);
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 		ivdp->vd_ndx = ndx;
6987c478bd9Sstevel@tonic-gate 		ivdp->vd_file = ifl;
6997c478bd9Sstevel@tonic-gate 		ivdp->vd_flags = vdf->vd_flags;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 		/*
7027c478bd9Sstevel@tonic-gate 		 * If we're processing a relocatable object then this version
7037c478bd9Sstevel@tonic-gate 		 * definition needs to be propagated to the output file.
7047c478bd9Sstevel@tonic-gate 		 * Generate a new output file version and associated this input
7057c478bd9Sstevel@tonic-gate 		 * version to it.  During symbol processing the version index of
7067c478bd9Sstevel@tonic-gate 		 * the symbol will be promoted from the input file to the output
7077c478bd9Sstevel@tonic-gate 		 * files version definition.
7087c478bd9Sstevel@tonic-gate 		 */
7097c478bd9Sstevel@tonic-gate 		if (relobj) {
7107c478bd9Sstevel@tonic-gate 			if (!(ofl->ofl_flags & FLG_OF_RELOBJ))
7117c478bd9Sstevel@tonic-gate 				ofl->ofl_flags |= FLG_OF_PROCRED;
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 			if ((ivdp->vd_flags & VER_FLG_BASE) == 0) {
7147c478bd9Sstevel@tonic-gate 				/*
7157c478bd9Sstevel@tonic-gate 				 * If no version descriptors have yet been set
7167c478bd9Sstevel@tonic-gate 				 * up, initialize a base version to represent
7177c478bd9Sstevel@tonic-gate 				 * the output file itself.  This `base' version
7187c478bd9Sstevel@tonic-gate 				 * catches any internally generated symbols
7197c478bd9Sstevel@tonic-gate 				 * (_end, _etext, etc.) and
7207c478bd9Sstevel@tonic-gate 				 * serves to initialize the output version
7217c478bd9Sstevel@tonic-gate 				 * descriptor count.
7227c478bd9Sstevel@tonic-gate 				 */
7237c478bd9Sstevel@tonic-gate 				if (ofl->ofl_vercnt == 0) {
7245aefb655Srie 					if (ld_vers_base(ofl) ==
7257c478bd9Sstevel@tonic-gate 					    (Ver_desc *)S_ERROR)
7267c478bd9Sstevel@tonic-gate 						return (S_ERROR);
7277c478bd9Sstevel@tonic-gate 				}
7287c478bd9Sstevel@tonic-gate 				ofl->ofl_flags |= FLG_OF_VERDEF;
7295aefb655Srie 				if ((ovdp = ld_vers_find(name, hash,
7307c478bd9Sstevel@tonic-gate 				    &ofl->ofl_verdesc)) == 0) {
7315aefb655Srie 					if ((ovdp = ld_vers_desc(name, hash,
7327c478bd9Sstevel@tonic-gate 					    &ofl->ofl_verdesc)) ==
7337c478bd9Sstevel@tonic-gate 					    (Ver_desc *)S_ERROR)
7347c478bd9Sstevel@tonic-gate 						return (S_ERROR);
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 					/* LINTED */
7377c478bd9Sstevel@tonic-gate 					ovdp->vd_ndx = (Half)++ofl->ofl_vercnt;
7387c478bd9Sstevel@tonic-gate 					ovdp->vd_file = ifl;
7397c478bd9Sstevel@tonic-gate 					ovdp->vd_flags = vdf->vd_flags;
7407c478bd9Sstevel@tonic-gate 				}
7417c478bd9Sstevel@tonic-gate 			}
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 			/*
7447c478bd9Sstevel@tonic-gate 			 * Maintain the association between the input version
7457c478bd9Sstevel@tonic-gate 			 * descriptor and the output version descriptor so that
7467c478bd9Sstevel@tonic-gate 			 * an associated symbols will be assigned to the
7477c478bd9Sstevel@tonic-gate 			 * correct version.
7487c478bd9Sstevel@tonic-gate 			 */
7497c478bd9Sstevel@tonic-gate 			ivdp->vd_ref = ovdp;
7507c478bd9Sstevel@tonic-gate 		}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 		/*
7537c478bd9Sstevel@tonic-gate 		 * Process any dependencies this version may have.
7547c478bd9Sstevel@tonic-gate 		 */
7557c478bd9Sstevel@tonic-gate 		vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next);
7567c478bd9Sstevel@tonic-gate 		for (cnt--; cnt; cnt--,
7577c478bd9Sstevel@tonic-gate 		    vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next)) {
7587c478bd9Sstevel@tonic-gate 			Ver_desc	*_ivdp;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 			name = (char *)(str + vdap->vda_name);
7617c478bd9Sstevel@tonic-gate 			/* LINTED */
7627c478bd9Sstevel@tonic-gate 			hash = (Word)elf_hash(name);
7637c478bd9Sstevel@tonic-gate 
7645aefb655Srie 			if ((_ivdp = ld_vers_find(name, hash,
7657c478bd9Sstevel@tonic-gate 			    &ifl->ifl_verdesc)) == 0) {
7665aefb655Srie 				if ((_ivdp = ld_vers_desc(name, hash,
7677c478bd9Sstevel@tonic-gate 				    &ifl->ifl_verdesc)) ==
7687c478bd9Sstevel@tonic-gate 				    (Ver_desc *)S_ERROR)
7697c478bd9Sstevel@tonic-gate 					return (S_ERROR);
7707c478bd9Sstevel@tonic-gate 			}
7717c478bd9Sstevel@tonic-gate 			if (list_appendc(&ivdp->vd_deps, _ivdp) == 0)
7727c478bd9Sstevel@tonic-gate 				return (S_ERROR);
7737c478bd9Sstevel@tonic-gate 		}
7745aefb655Srie 		DBG_CALL(Dbg_ver_desc_entry(ofl->ofl_lml, ivdp));
7757c478bd9Sstevel@tonic-gate 	}
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	/*
7787c478bd9Sstevel@tonic-gate 	 * Now that we know the total number of version definitions for this
7797c478bd9Sstevel@tonic-gate 	 * file, build an index array for fast access when processing symbols.
7807c478bd9Sstevel@tonic-gate 	 */
7815aefb655Srie 	if ((ifl->ifl_verndx =
7825aefb655Srie 	    vers_index(ofl, ifl, relobj)) == (Ver_index *)S_ERROR)
7837c478bd9Sstevel@tonic-gate 		return (S_ERROR);
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	if (relobj)
7867c478bd9Sstevel@tonic-gate 		return (1);
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	/*
7897c478bd9Sstevel@tonic-gate 	 * If this object has version control definitions against it then these
7907c478bd9Sstevel@tonic-gate 	 * must be processed so as to select those version definitions to which
7917c478bd9Sstevel@tonic-gate 	 * symbol bindings can occur.  Otherwise simply mark all versions as
7927c478bd9Sstevel@tonic-gate 	 * available.
7937c478bd9Sstevel@tonic-gate 	 */
7945aefb655Srie 	DBG_CALL(Dbg_ver_avail_title(ofl->ofl_lml, file));
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	if (sdf && (sdf->sdf_flags & FLG_SDF_SELECT)) {
7977c478bd9Sstevel@tonic-gate 		Listnode	*lnp1;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&sdf->sdf_vers, lnp1, sdv)) {
8007c478bd9Sstevel@tonic-gate 			Listnode	*lnp2;
8017c478bd9Sstevel@tonic-gate 			Ver_desc	*vdp;
8027c478bd9Sstevel@tonic-gate 			int		found = 0;
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 			for (LIST_TRAVERSE(&ifl->ifl_verdesc, lnp2, vdp)) {
8057c478bd9Sstevel@tonic-gate 				if (strcmp(sdv->sdv_name, vdp->vd_name) == 0) {
8067c478bd9Sstevel@tonic-gate 					found++;
8077c478bd9Sstevel@tonic-gate 					break;
8087c478bd9Sstevel@tonic-gate 				}
8097c478bd9Sstevel@tonic-gate 			}
8107c478bd9Sstevel@tonic-gate 			if (found)
8115aefb655Srie 				vers_select(ofl, ifl, vdp, sdv->sdv_ref);
8127c478bd9Sstevel@tonic-gate 			else {
8135aefb655Srie 				eprintf(ofl->ofl_lml, ERR_FATAL,
8145aefb655Srie 				    MSG_INTL(MSG_VER_NOEXIST), ifl->ifl_name,
8155aefb655Srie 				    sdv->sdv_name, sdv->sdv_ref);
8167c478bd9Sstevel@tonic-gate 				ofl->ofl_flags |= FLG_OF_FATAL;
8177c478bd9Sstevel@tonic-gate 			}
8187c478bd9Sstevel@tonic-gate 		}
8197c478bd9Sstevel@tonic-gate 	} else {
8207c478bd9Sstevel@tonic-gate 		Ver_index	*vip;
8217c478bd9Sstevel@tonic-gate 		int		cnt;
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 		for (cnt = VER_NDX_GLOBAL; cnt <= ifl->ifl_vercnt; cnt++) {
8247c478bd9Sstevel@tonic-gate 			vip = &ifl->ifl_verndx[cnt];
8257c478bd9Sstevel@tonic-gate 			vip->vi_flags |= FLG_VER_AVAIL;
8265aefb655Srie 			DBG_CALL(Dbg_ver_avail_entry(ofl->ofl_lml, vip, 0));
8277c478bd9Sstevel@tonic-gate 		}
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	/*
8317c478bd9Sstevel@tonic-gate 	 * If this is an explict dependency indicate that this file is a
8327c478bd9Sstevel@tonic-gate 	 * candidate for requiring version needed information to be recorded in
8337c478bd9Sstevel@tonic-gate 	 * the image we're creating.
8347c478bd9Sstevel@tonic-gate 	 */
8357c478bd9Sstevel@tonic-gate 	if (ifl->ifl_flags & FLG_IF_NEEDED)
8367c478bd9Sstevel@tonic-gate 		ofl->ofl_flags |= FLG_OF_VERNEED;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	return (1);
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate /*
8427c478bd9Sstevel@tonic-gate  * Process a version needed section.
8437c478bd9Sstevel@tonic-gate  */
8447c478bd9Sstevel@tonic-gate uintptr_t
8455aefb655Srie ld_vers_need_process(Is_desc *isp, Ifl_desc *ifl, Ofl_desc *ofl)
8467c478bd9Sstevel@tonic-gate {
8477c478bd9Sstevel@tonic-gate 	const char	*str, *file = ifl->ifl_name;
8487c478bd9Sstevel@tonic-gate 	Word		num, _num;
8497c478bd9Sstevel@tonic-gate 	Verneed		*vnd;
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	vnd = (Verneed *)isp->is_indata->d_buf;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	/*
8547c478bd9Sstevel@tonic-gate 	 * Verify the version revision.  We only check the first version
8557c478bd9Sstevel@tonic-gate 	 * structure as it is assumed all other version structures in this
8567c478bd9Sstevel@tonic-gate 	 * data section will be of the same revision.
8577c478bd9Sstevel@tonic-gate 	 */
8585aefb655Srie 	if (vnd->vn_version > VER_DEF_CURRENT) {
8595aefb655Srie 		(void) eprintf(ofl->ofl_lml, ERR_WARNING,
8605aefb655Srie 		    MSG_INTL(MSG_VER_HIGHER), ifl->ifl_name, vnd->vn_version,
8615aefb655Srie 		    VER_DEF_CURRENT);
8625aefb655Srie 	}
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	num = isp->is_shdr->sh_info;
8657c478bd9Sstevel@tonic-gate 	str = (char *)ifl->ifl_isdesc[isp->is_shdr->sh_link]->is_indata->d_buf;
8667c478bd9Sstevel@tonic-gate 
8675aefb655Srie 	DBG_CALL(Dbg_ver_need_title(ofl->ofl_lml, file));
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	/*
8707c478bd9Sstevel@tonic-gate 	 * Loop through the version information setting up a version descriptor
8717c478bd9Sstevel@tonic-gate 	 * for each version definition.
8727c478bd9Sstevel@tonic-gate 	 */
8737c478bd9Sstevel@tonic-gate 	for (_num = 1; _num <= num; _num++,
8747c478bd9Sstevel@tonic-gate 	    vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
8757c478bd9Sstevel@tonic-gate 		Sdf_desc	*sdf;
8767c478bd9Sstevel@tonic-gate 		Sdv_desc	*sdv;
8777c478bd9Sstevel@tonic-gate 		const char	*name;
8787c478bd9Sstevel@tonic-gate 		Half		cnt = vnd->vn_cnt;
8797c478bd9Sstevel@tonic-gate 		Vernaux		*vnap = (Vernaux *)((uintptr_t)vnd +
88060758829Srie 		    vnd->vn_aux);
8817c478bd9Sstevel@tonic-gate 		Half		_cnt;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 		name = (char *)(str + vnd->vn_file);
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 		/*
8867c478bd9Sstevel@tonic-gate 		 * Set up a shared object descriptor and add to it the necessary
8877c478bd9Sstevel@tonic-gate 		 * needed versions.  This information may also have been added
8887c478bd9Sstevel@tonic-gate 		 * by a mapfile (see map_dash()).
8897c478bd9Sstevel@tonic-gate 		 */
8907c478bd9Sstevel@tonic-gate 		if ((sdf = sdf_find(name, &ofl->ofl_soneed)) == 0) {
8917c478bd9Sstevel@tonic-gate 			if ((sdf = sdf_add(name, &ofl->ofl_soneed)) ==
8927c478bd9Sstevel@tonic-gate 			    (Sdf_desc *)S_ERROR)
8937c478bd9Sstevel@tonic-gate 				return (S_ERROR);
8947c478bd9Sstevel@tonic-gate 			sdf->sdf_rfile = file;
8957c478bd9Sstevel@tonic-gate 			sdf->sdf_flags |= FLG_SDF_VERIFY;
8967c478bd9Sstevel@tonic-gate 		}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 		for (_cnt = 0; cnt; _cnt++, cnt--,
8997c478bd9Sstevel@tonic-gate 		    vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next)) {
9007c478bd9Sstevel@tonic-gate 			if (!(sdv =
9017c478bd9Sstevel@tonic-gate 			    libld_calloc(sizeof (Sdv_desc), 1)))
9027c478bd9Sstevel@tonic-gate 				return (S_ERROR);
9037c478bd9Sstevel@tonic-gate 			sdv->sdv_name = str + vnap->vna_name;
9047c478bd9Sstevel@tonic-gate 			sdv->sdv_ref = file;
9057c478bd9Sstevel@tonic-gate 			if (list_appendc(&sdf->sdf_vers, sdv) == 0)
9067c478bd9Sstevel@tonic-gate 				return (S_ERROR);
9075aefb655Srie 			DBG_CALL(Dbg_ver_need_entry(ofl->ofl_lml, _cnt, name,
9085aefb655Srie 			    sdv->sdv_name));
9097c478bd9Sstevel@tonic-gate 		}
9107c478bd9Sstevel@tonic-gate 	}
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	return (1);
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate /*
9167c478bd9Sstevel@tonic-gate  * If a symbol is obtained from a versioned relocatable object then the symbols
9177c478bd9Sstevel@tonic-gate  * version association must be promoted to the version definition as it will be
9187c478bd9Sstevel@tonic-gate  * represented in the output file.
9197c478bd9Sstevel@tonic-gate  */
9207c478bd9Sstevel@tonic-gate void
9215aefb655Srie ld_vers_promote(Sym_desc *sdp, Word ndx, Ifl_desc *ifl, Ofl_desc *ofl)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	Half 	vndx;
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	/*
9267c478bd9Sstevel@tonic-gate 	 * A version symbol index of 0 implies the symbol is local.  A value of
9277c478bd9Sstevel@tonic-gate 	 * VER_NDX_GLOBAL implies the symbol is global but has not been
9287c478bd9Sstevel@tonic-gate 	 * assigned to a specfic version definition.
9297c478bd9Sstevel@tonic-gate 	 */
9307c478bd9Sstevel@tonic-gate 	vndx = ifl->ifl_versym[ndx];
9317c478bd9Sstevel@tonic-gate 	if (vndx == 0) {
9327c478bd9Sstevel@tonic-gate 		sdp->sd_flags |= FLG_SY_REDUCED;
93360758829Srie 		sdp->sd_flags1 |= FLG_SY1_HIDDEN;
9347c478bd9Sstevel@tonic-gate 		return;
9357c478bd9Sstevel@tonic-gate 	}
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	if (vndx == VER_NDX_ELIMINATE) {
9387c478bd9Sstevel@tonic-gate 		sdp->sd_flags |= FLG_SY_REDUCED;
93960758829Srie 		sdp->sd_flags1 |= (FLG_SY1_HIDDEN | FLG_SY1_ELIM);
9407c478bd9Sstevel@tonic-gate 		return;
9417c478bd9Sstevel@tonic-gate 	}
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	if (vndx == VER_NDX_GLOBAL) {
94460758829Srie 		if ((sdp->sd_flags1 & FLG_SY1_HIDDEN) == 0)
94560758829Srie 			sdp->sd_flags1 |= (FLG_SY1_DEFAULT | FLG_SY1_EXPDEF);
94660758829Srie 		if (sdp->sd_aux->sa_overndx <= VER_NDX_GLOBAL)
9477c478bd9Sstevel@tonic-gate 			sdp->sd_aux->sa_overndx = VER_NDX_GLOBAL;
9487c478bd9Sstevel@tonic-gate 		return;
9497c478bd9Sstevel@tonic-gate 	}
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	/*
9527c478bd9Sstevel@tonic-gate 	 * Any other version index requires association to the appropriate
9537c478bd9Sstevel@tonic-gate 	 * version definition.
9547c478bd9Sstevel@tonic-gate 	 */
9557c478bd9Sstevel@tonic-gate 	if ((ifl->ifl_verndx == 0) || (vndx > ifl->ifl_vercnt)) {
9565aefb655Srie 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_VER_INVALNDX),
9575aefb655Srie 		    sdp->sd_name, ifl->ifl_name, vndx);
9587c478bd9Sstevel@tonic-gate 		ofl->ofl_flags |= FLG_OF_FATAL;
9597c478bd9Sstevel@tonic-gate 		return;
9607c478bd9Sstevel@tonic-gate 	}
9617c478bd9Sstevel@tonic-gate 
96260758829Srie 	if ((sdp->sd_flags1 & FLG_SY1_HIDDEN) == 0)
96360758829Srie 		sdp->sd_flags1 |= (FLG_SY1_DEFAULT | FLG_SY1_EXPDEF);
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	/*
9667c478bd9Sstevel@tonic-gate 	 * Promote the symbols version index to the appropriate output version
9677c478bd9Sstevel@tonic-gate 	 * definition.
9687c478bd9Sstevel@tonic-gate 	 */
9697c478bd9Sstevel@tonic-gate 	if (!(sdp->sd_flags & FLG_SY_VERSPROM)) {
9707c478bd9Sstevel@tonic-gate 		Ver_index	*vip;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 		vip = &ifl->ifl_verndx[vndx];
9737c478bd9Sstevel@tonic-gate 		sdp->sd_aux->sa_overndx = vip->vi_desc->vd_ref->vd_ndx;
9747c478bd9Sstevel@tonic-gate 		sdp->sd_flags |= FLG_SY_VERSPROM;
9757c478bd9Sstevel@tonic-gate 	}
9767c478bd9Sstevel@tonic-gate }
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate /*
9797c478bd9Sstevel@tonic-gate  * If any versioning is called for make sure an initial version descriptor is
9807c478bd9Sstevel@tonic-gate  * assigned to represent the file itself.  Known as the base version.
9817c478bd9Sstevel@tonic-gate  */
9827c478bd9Sstevel@tonic-gate Ver_desc *
9835aefb655Srie ld_vers_base(Ofl_desc *ofl)
9847c478bd9Sstevel@tonic-gate {
9857c478bd9Sstevel@tonic-gate 	Ver_desc	*vdp;
9867c478bd9Sstevel@tonic-gate 	const char	*name;
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	/*
9897c478bd9Sstevel@tonic-gate 	 * Determine the filename to associate to the version descriptor.  This
9907c478bd9Sstevel@tonic-gate 	 * is either the SONAME (if one has been supplied) or the basename of
9917c478bd9Sstevel@tonic-gate 	 * the output file.
9927c478bd9Sstevel@tonic-gate 	 */
9937c478bd9Sstevel@tonic-gate 	if ((name = ofl->ofl_soname) == 0) {
9947c478bd9Sstevel@tonic-gate 		const char	*str = ofl->ofl_name;
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 		while (*str != '\0') {
9977c478bd9Sstevel@tonic-gate 			if (*str++ == '/')
9987c478bd9Sstevel@tonic-gate 				name = str;
9997c478bd9Sstevel@tonic-gate 		}
10007c478bd9Sstevel@tonic-gate 		if (name == 0)
10017c478bd9Sstevel@tonic-gate 			name = ofl->ofl_name;
10027c478bd9Sstevel@tonic-gate 	}
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	/*
10057c478bd9Sstevel@tonic-gate 	 * Generate the version descriptor.
10067c478bd9Sstevel@tonic-gate 	 */
10077c478bd9Sstevel@tonic-gate 	/* LINTED */
10085aefb655Srie 	if ((vdp = ld_vers_desc(name, (Word)elf_hash(name),
10095aefb655Srie 	    &ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR)
10107c478bd9Sstevel@tonic-gate 		return ((Ver_desc *)S_ERROR);
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	/*
10137c478bd9Sstevel@tonic-gate 	 * Assign the base index to this version and initialize the output file
10147c478bd9Sstevel@tonic-gate 	 * descriptor with the number of version descriptors presently in use.
10157c478bd9Sstevel@tonic-gate 	 */
10167c478bd9Sstevel@tonic-gate 	vdp->vd_ndx = ofl->ofl_vercnt = VER_NDX_GLOBAL;
10177c478bd9Sstevel@tonic-gate 	vdp->vd_flags |= VER_FLG_BASE;
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	return (vdp);
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate /*
10237c478bd9Sstevel@tonic-gate  * Now that all input shared objects have been processed, verify that all
10247c478bd9Sstevel@tonic-gate  * version requirements have been met.  Any version control requirements will
10257c478bd9Sstevel@tonic-gate  * have been specified by the user (and placed on the ofl_oscntl list) and are
10267c478bd9Sstevel@tonic-gate  * verified at the time the object was processed (see ver_def_process()).
10277c478bd9Sstevel@tonic-gate  * Here we process all version requirements established from shared objects
10287c478bd9Sstevel@tonic-gate  * themselves (ie,. NEEDED dependencies).
10297c478bd9Sstevel@tonic-gate  */
10307c478bd9Sstevel@tonic-gate int
10315aefb655Srie ld_vers_verify(Ofl_desc *ofl)
10327c478bd9Sstevel@tonic-gate {
10337c478bd9Sstevel@tonic-gate 	Listnode	*lnp1;
10347c478bd9Sstevel@tonic-gate 	Sdf_desc	*sdf;
10357c478bd9Sstevel@tonic-gate 	char		*nv;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	/*
10387c478bd9Sstevel@tonic-gate 	 * As with the runtime environment, disable all version verification if
10397c478bd9Sstevel@tonic-gate 	 * requested.
10407c478bd9Sstevel@tonic-gate 	 */
10417c478bd9Sstevel@tonic-gate #if	defined(_ELF64)
10427c478bd9Sstevel@tonic-gate 	if ((nv = getenv(MSG_ORIG(MSG_LD_NOVERSION_64))) == NULL)
10437c478bd9Sstevel@tonic-gate #else
10447c478bd9Sstevel@tonic-gate 	if ((nv = getenv(MSG_ORIG(MSG_LD_NOVERSION_32))) == NULL)
10457c478bd9Sstevel@tonic-gate #endif
104660758829Srie 		nv = getenv(MSG_ORIG(MSG_LD_NOVERSION));
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 	if (nv && (*nv != '\0'))
10497c478bd9Sstevel@tonic-gate 		return (1);
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ofl->ofl_soneed, lnp1, sdf)) {
10527c478bd9Sstevel@tonic-gate 		Listnode	*lnp2;
10537c478bd9Sstevel@tonic-gate 		Sdv_desc	*sdv;
10547c478bd9Sstevel@tonic-gate 		Ifl_desc	*ifl = sdf->sdf_file;
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 		if (!(sdf->sdf_flags & FLG_SDF_VERIFY))
10577c478bd9Sstevel@tonic-gate 			continue;
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 		/*
10607c478bd9Sstevel@tonic-gate 		 * If this file contains no version definitions then ignore
10617c478bd9Sstevel@tonic-gate 		 * any versioning verification.  This is the same model as
10627c478bd9Sstevel@tonic-gate 		 * carried out by ld.so.1 and is intended to allow backward
10637c478bd9Sstevel@tonic-gate 		 * compatibility should a shared object with a version
10647c478bd9Sstevel@tonic-gate 		 * requirment be returned to an older system on which a
10657c478bd9Sstevel@tonic-gate 		 * non-versioned shared object exists.
10667c478bd9Sstevel@tonic-gate 		 */
10677c478bd9Sstevel@tonic-gate 		if ((ifl == 0) || (ifl->ifl_verdesc.head == 0))
10687c478bd9Sstevel@tonic-gate 			continue;
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 		/*
10717c478bd9Sstevel@tonic-gate 		 * If individual versions were specified for this file make
10727c478bd9Sstevel@tonic-gate 		 * sure that they actually exist in the appropriate file, and
10737c478bd9Sstevel@tonic-gate 		 * that they are available for binding.
10747c478bd9Sstevel@tonic-gate 		 */
10757c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&sdf->sdf_vers, lnp2, sdv)) {
10767c478bd9Sstevel@tonic-gate 			Listnode	*lnp3;
10777c478bd9Sstevel@tonic-gate 			Ver_desc	*vdp;
10787c478bd9Sstevel@tonic-gate 			int		found = 0;
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 			for (LIST_TRAVERSE(&ifl->ifl_verdesc, lnp3, vdp)) {
10817c478bd9Sstevel@tonic-gate 				if (strcmp(sdv->sdv_name, vdp->vd_name) == 0) {
10827c478bd9Sstevel@tonic-gate 					found++;
10837c478bd9Sstevel@tonic-gate 					break;
10847c478bd9Sstevel@tonic-gate 				}
10857c478bd9Sstevel@tonic-gate 			}
10867c478bd9Sstevel@tonic-gate 			if (found) {
10877c478bd9Sstevel@tonic-gate 				Ver_index	*vip;
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 				vip = &ifl->ifl_verndx[vdp->vd_ndx];
10907c478bd9Sstevel@tonic-gate 				if (!(vip->vi_flags & FLG_VER_AVAIL)) {
10915aefb655Srie 					eprintf(ofl->ofl_lml, ERR_FATAL,
10927c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_VER_UNAVAIL),
10937c478bd9Sstevel@tonic-gate 					    ifl->ifl_name, sdv->sdv_name,
10947c478bd9Sstevel@tonic-gate 					    sdv->sdv_ref);
10957c478bd9Sstevel@tonic-gate 					ofl->ofl_flags |= FLG_OF_FATAL;
10967c478bd9Sstevel@tonic-gate 				}
10977c478bd9Sstevel@tonic-gate 			} else {
10985aefb655Srie 				eprintf(ofl->ofl_lml, ERR_FATAL,
10995aefb655Srie 				    MSG_INTL(MSG_VER_NOEXIST), ifl->ifl_name,
11005aefb655Srie 				    sdv->sdv_name, sdv->sdv_ref);
11017c478bd9Sstevel@tonic-gate 				ofl->ofl_flags |= FLG_OF_FATAL;
11027c478bd9Sstevel@tonic-gate 			}
11037c478bd9Sstevel@tonic-gate 		}
11047c478bd9Sstevel@tonic-gate 	}
11057c478bd9Sstevel@tonic-gate 	return (1);
11067c478bd9Sstevel@tonic-gate }
1107