xref: /illumos-gate/usr/src/cmd/sgs/libld/common/version.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #include	<string.h>
29*7c478bd9Sstevel@tonic-gate #include	<stdio.h>
30*7c478bd9Sstevel@tonic-gate #include	"debug.h"
31*7c478bd9Sstevel@tonic-gate #include	"msg.h"
32*7c478bd9Sstevel@tonic-gate #include	"_libld.h"
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate /*
36*7c478bd9Sstevel@tonic-gate  * Locate a version descriptor.
37*7c478bd9Sstevel@tonic-gate  */
38*7c478bd9Sstevel@tonic-gate Ver_desc *
39*7c478bd9Sstevel@tonic-gate vers_find(const char *name, Word hash, List *lst)
40*7c478bd9Sstevel@tonic-gate {
41*7c478bd9Sstevel@tonic-gate 	Listnode	*lnp;
42*7c478bd9Sstevel@tonic-gate 	Ver_desc	*vdp;
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(lst, lnp, vdp)) {
45*7c478bd9Sstevel@tonic-gate 		if (vdp->vd_hash != hash)
46*7c478bd9Sstevel@tonic-gate 			continue;
47*7c478bd9Sstevel@tonic-gate 		if (strcmp(vdp->vd_name, name) == 0)
48*7c478bd9Sstevel@tonic-gate 			return (vdp);
49*7c478bd9Sstevel@tonic-gate 	}
50*7c478bd9Sstevel@tonic-gate 	return (0);
51*7c478bd9Sstevel@tonic-gate }
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /*
54*7c478bd9Sstevel@tonic-gate  * Add a new version descriptor to a version descriptor list.  Note, users of
55*7c478bd9Sstevel@tonic-gate  * this are responsible for determining if the version descriptor already
56*7c478bd9Sstevel@tonic-gate  * exists (this can reduce the need to allocate storage for descriptor names
57*7c478bd9Sstevel@tonic-gate  * until it is determined a descriptor need be created (see map_symbol())).
58*7c478bd9Sstevel@tonic-gate  */
59*7c478bd9Sstevel@tonic-gate Ver_desc *
60*7c478bd9Sstevel@tonic-gate vers_desc(const char *name, Word hash, List *lst)
61*7c478bd9Sstevel@tonic-gate {
62*7c478bd9Sstevel@tonic-gate 	Ver_desc	*vdp;
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	if ((vdp = libld_calloc(sizeof (Ver_desc), 1)) == 0)
65*7c478bd9Sstevel@tonic-gate 		return ((Ver_desc *)S_ERROR);
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 	vdp->vd_name = name;
68*7c478bd9Sstevel@tonic-gate 	vdp->vd_hash = hash;
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 	if (list_appendc(lst, vdp) == 0)
71*7c478bd9Sstevel@tonic-gate 		return ((Ver_desc *)S_ERROR);
72*7c478bd9Sstevel@tonic-gate 	else
73*7c478bd9Sstevel@tonic-gate 		return (vdp);
74*7c478bd9Sstevel@tonic-gate }
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate /*
77*7c478bd9Sstevel@tonic-gate  * Now that all explict files have been processed validate any version
78*7c478bd9Sstevel@tonic-gate  * definitions.  Insure that any version references are available (a version
79*7c478bd9Sstevel@tonic-gate  * has been defined when it's been assigned an index).  Also calculate the
80*7c478bd9Sstevel@tonic-gate  * number of .version section entries that will be required to hold this
81*7c478bd9Sstevel@tonic-gate  * information.
82*7c478bd9Sstevel@tonic-gate  */
83*7c478bd9Sstevel@tonic-gate #define	_NUM_OF_VERS_	40	/* twice as big as the depth for libc version */
84*7c478bd9Sstevel@tonic-gate typedef struct {
85*7c478bd9Sstevel@tonic-gate 	Ver_desc	**ver_stk;
86*7c478bd9Sstevel@tonic-gate 	int 		ver_sp;
87*7c478bd9Sstevel@tonic-gate 	int 		ver_lmt;
88*7c478bd9Sstevel@tonic-gate } Ver_Stack;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate static uintptr_t
91*7c478bd9Sstevel@tonic-gate vers_visit_children(Ver_desc *vp, int flag)
92*7c478bd9Sstevel@tonic-gate {
93*7c478bd9Sstevel@tonic-gate 	Listnode		*lnp1;
94*7c478bd9Sstevel@tonic-gate 	Ver_desc		*vdp;
95*7c478bd9Sstevel@tonic-gate 	static int		err = 0;
96*7c478bd9Sstevel@tonic-gate 	static Ver_Stack	ver_stk = {0, 0, 0};
97*7c478bd9Sstevel@tonic-gate 	int			tmp_sp;
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	/*
100*7c478bd9Sstevel@tonic-gate 	 * If there was any fatal error,
101*7c478bd9Sstevel@tonic-gate 	 * just return.
102*7c478bd9Sstevel@tonic-gate 	 */
103*7c478bd9Sstevel@tonic-gate 	if (err == S_ERROR)
104*7c478bd9Sstevel@tonic-gate 		return (err);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	/*
107*7c478bd9Sstevel@tonic-gate 	 * if this is called from, ver_check_defs(), initialize sp.
108*7c478bd9Sstevel@tonic-gate 	 */
109*7c478bd9Sstevel@tonic-gate 	if (flag == 0)
110*7c478bd9Sstevel@tonic-gate 		ver_stk.ver_sp = 0;
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	/*
113*7c478bd9Sstevel@tonic-gate 	 * Check if passed version pointer vp is already in the stack.
114*7c478bd9Sstevel@tonic-gate 	 */
115*7c478bd9Sstevel@tonic-gate 	for (tmp_sp = 0; tmp_sp < ver_stk.ver_sp; tmp_sp++) {
116*7c478bd9Sstevel@tonic-gate 		Ver_desc *v;
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 		v = ver_stk.ver_stk[tmp_sp];
119*7c478bd9Sstevel@tonic-gate 		if (v == vp) {
120*7c478bd9Sstevel@tonic-gate 			/*
121*7c478bd9Sstevel@tonic-gate 			 * cyclic dependency.
122*7c478bd9Sstevel@tonic-gate 			 */
123*7c478bd9Sstevel@tonic-gate 			if (err == 0) {
124*7c478bd9Sstevel@tonic-gate 				eprintf(ERR_FATAL, MSG_INTL(MSG_VER_CYCLIC));
125*7c478bd9Sstevel@tonic-gate 				err = 1;
126*7c478bd9Sstevel@tonic-gate 			}
127*7c478bd9Sstevel@tonic-gate 			for (tmp_sp = 0; tmp_sp < ver_stk.ver_sp; tmp_sp++) {
128*7c478bd9Sstevel@tonic-gate 				v = ver_stk.ver_stk[tmp_sp];
129*7c478bd9Sstevel@tonic-gate 				if ((v->vd_flags & FLG_VER_CYCLIC) == 0) {
130*7c478bd9Sstevel@tonic-gate 					v->vd_flags |= FLG_VER_CYCLIC;
131*7c478bd9Sstevel@tonic-gate 					eprintf(ERR_NONE,
132*7c478bd9Sstevel@tonic-gate 						MSG_INTL(MSG_VER_ADDVER),
133*7c478bd9Sstevel@tonic-gate 						v->vd_name);
134*7c478bd9Sstevel@tonic-gate 				}
135*7c478bd9Sstevel@tonic-gate 			}
136*7c478bd9Sstevel@tonic-gate 			if ((vp->vd_flags & FLG_VER_CYCLIC) == 0) {
137*7c478bd9Sstevel@tonic-gate 				vp->vd_flags |= FLG_VER_CYCLIC;
138*7c478bd9Sstevel@tonic-gate 				eprintf(ERR_NONE,
139*7c478bd9Sstevel@tonic-gate 					MSG_INTL(MSG_VER_ADDVER),
140*7c478bd9Sstevel@tonic-gate 					vp->vd_name);
141*7c478bd9Sstevel@tonic-gate 			}
142*7c478bd9Sstevel@tonic-gate 			return (err);
143*7c478bd9Sstevel@tonic-gate 		}
144*7c478bd9Sstevel@tonic-gate 	}
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	/*
147*7c478bd9Sstevel@tonic-gate 	 * Push version on the stack.
148*7c478bd9Sstevel@tonic-gate 	 */
149*7c478bd9Sstevel@tonic-gate 	if (ver_stk.ver_sp >= ver_stk.ver_lmt) {
150*7c478bd9Sstevel@tonic-gate 		ver_stk.ver_lmt += _NUM_OF_VERS_;
151*7c478bd9Sstevel@tonic-gate 		if ((ver_stk.ver_stk = (Ver_desc **)
152*7c478bd9Sstevel@tonic-gate 		    libld_realloc((void *)ver_stk.ver_stk,
153*7c478bd9Sstevel@tonic-gate 		    ver_stk.ver_lmt * sizeof (Ver_desc *))) == NULL)
154*7c478bd9Sstevel@tonic-gate 			return (S_ERROR);
155*7c478bd9Sstevel@tonic-gate 	}
156*7c478bd9Sstevel@tonic-gate 	ver_stk.ver_stk[(ver_stk.ver_sp)++] = vp;
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	/*
159*7c478bd9Sstevel@tonic-gate 	 * Now visit children.
160*7c478bd9Sstevel@tonic-gate 	 */
161*7c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&vp->vd_deps, lnp1, vdp))
162*7c478bd9Sstevel@tonic-gate 		if (vers_visit_children(vdp, 1) == S_ERROR)
163*7c478bd9Sstevel@tonic-gate 			return (S_ERROR);
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	/*
166*7c478bd9Sstevel@tonic-gate 	 * Pop version from the stack.
167*7c478bd9Sstevel@tonic-gate 	 */
168*7c478bd9Sstevel@tonic-gate 	(ver_stk.ver_sp)--;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	return (err);
171*7c478bd9Sstevel@tonic-gate }
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate uintptr_t
174*7c478bd9Sstevel@tonic-gate vers_check_defs(Ofl_desc *ofl)
175*7c478bd9Sstevel@tonic-gate {
176*7c478bd9Sstevel@tonic-gate 	Listnode	*lnp1, *lnp2;
177*7c478bd9Sstevel@tonic-gate 	Ver_desc	*vdp;
178*7c478bd9Sstevel@tonic-gate 	uintptr_t 	is_cyclic = 0;
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	DBG_CALL(Dbg_ver_def_title(ofl->ofl_name));
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	/*
184*7c478bd9Sstevel@tonic-gate 	 * First check if there are any cyclic dependency
185*7c478bd9Sstevel@tonic-gate 	 */
186*7c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ofl->ofl_verdesc, lnp1, vdp))
187*7c478bd9Sstevel@tonic-gate 		if ((is_cyclic = vers_visit_children(vdp, 0)) == S_ERROR)
188*7c478bd9Sstevel@tonic-gate 			return (S_ERROR);
189*7c478bd9Sstevel@tonic-gate 	if (is_cyclic)
190*7c478bd9Sstevel@tonic-gate 		ofl->ofl_flags |= FLG_OF_FATAL;
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ofl->ofl_verdesc, lnp1, vdp)) {
193*7c478bd9Sstevel@tonic-gate 		Byte		cnt;
194*7c478bd9Sstevel@tonic-gate 		Sym		*sym;
195*7c478bd9Sstevel@tonic-gate 		Sym_desc	*sdp;
196*7c478bd9Sstevel@tonic-gate 		const char	*name = vdp->vd_name;
197*7c478bd9Sstevel@tonic-gate 		unsigned char	bind;
198*7c478bd9Sstevel@tonic-gate 		Ver_desc	*_vdp;
199*7c478bd9Sstevel@tonic-gate 		avl_index_t	where;
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 		if (vdp->vd_ndx == 0) {
202*7c478bd9Sstevel@tonic-gate 			eprintf(ERR_FATAL, MSG_INTL(MSG_VER_UNDEF), name,
203*7c478bd9Sstevel@tonic-gate 			    vdp->vd_ref->vd_name,
204*7c478bd9Sstevel@tonic-gate 			    vdp->vd_ref->vd_file->ifl_name);
205*7c478bd9Sstevel@tonic-gate 			ofl->ofl_flags |= FLG_OF_FATAL;
206*7c478bd9Sstevel@tonic-gate 			continue;
207*7c478bd9Sstevel@tonic-gate 		}
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 		DBG_CALL(Dbg_ver_desc_entry(vdp));
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 		/*
212*7c478bd9Sstevel@tonic-gate 		 * If a version definition contains no symbols this is possibly
213*7c478bd9Sstevel@tonic-gate 		 * a mapfile error.
214*7c478bd9Sstevel@tonic-gate 		 */
215*7c478bd9Sstevel@tonic-gate 		if ((vdp->vd_flags &
216*7c478bd9Sstevel@tonic-gate 		    (VER_FLG_BASE | VER_FLG_WEAK | FLG_VER_REFER)) == 0)
217*7c478bd9Sstevel@tonic-gate 			DBG_CALL(Dbg_ver_nointerface(vdp->vd_name));
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 		/*
220*7c478bd9Sstevel@tonic-gate 		 * Update the version entry count to account for this new
221*7c478bd9Sstevel@tonic-gate 		 * version descriptor (the count is the size in bytes).
222*7c478bd9Sstevel@tonic-gate 		 */
223*7c478bd9Sstevel@tonic-gate 		ofl->ofl_verdefsz += sizeof (Verdef);
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 		/*
226*7c478bd9Sstevel@tonic-gate 		 * Traverse this versions dependency list to determine what
227*7c478bd9Sstevel@tonic-gate 		 * additional version dependencies we must account for against
228*7c478bd9Sstevel@tonic-gate 		 * this descriptor.
229*7c478bd9Sstevel@tonic-gate 		 */
230*7c478bd9Sstevel@tonic-gate 		cnt = 1;
231*7c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&vdp->vd_deps, lnp2, _vdp)) {
232*7c478bd9Sstevel@tonic-gate #if	defined(__lint)
233*7c478bd9Sstevel@tonic-gate 			/* get lint to think `_vdp' is used... */
234*7c478bd9Sstevel@tonic-gate 			lnp2 = (Listnode *)_vdp;
235*7c478bd9Sstevel@tonic-gate #endif
236*7c478bd9Sstevel@tonic-gate 			cnt++;
237*7c478bd9Sstevel@tonic-gate 		}
238*7c478bd9Sstevel@tonic-gate 		ofl->ofl_verdefsz += (cnt * sizeof (Verdaux));
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 		/*
241*7c478bd9Sstevel@tonic-gate 		 * Except for the base version descriptor, generate an absolute
242*7c478bd9Sstevel@tonic-gate 		 * symbol to reflect this version.
243*7c478bd9Sstevel@tonic-gate 		 */
244*7c478bd9Sstevel@tonic-gate 		if (vdp->vd_flags & VER_FLG_BASE)
245*7c478bd9Sstevel@tonic-gate 			continue;
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 		if (vdp->vd_flags & VER_FLG_WEAK)
248*7c478bd9Sstevel@tonic-gate 			bind = STB_WEAK;
249*7c478bd9Sstevel@tonic-gate 		else
250*7c478bd9Sstevel@tonic-gate 			bind = STB_GLOBAL;
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 		if (sdp = sym_find(name, vdp->vd_hash, &where, ofl)) {
253*7c478bd9Sstevel@tonic-gate 			/*
254*7c478bd9Sstevel@tonic-gate 			 * If the symbol already exists and is undefined or was
255*7c478bd9Sstevel@tonic-gate 			 * defined in a shared library, convert it to an
256*7c478bd9Sstevel@tonic-gate 			 * absolute.
257*7c478bd9Sstevel@tonic-gate 			 */
258*7c478bd9Sstevel@tonic-gate 			if ((sdp->sd_shndx == SHN_UNDEF) ||
259*7c478bd9Sstevel@tonic-gate 			    (sdp->sd_ref != REF_REL_NEED)) {
260*7c478bd9Sstevel@tonic-gate 				sdp->sd_shndx = sdp->sd_sym->st_shndx = SHN_ABS;
261*7c478bd9Sstevel@tonic-gate 				sdp->sd_sym->st_info =
262*7c478bd9Sstevel@tonic-gate 					ELF_ST_INFO(bind, STT_OBJECT);
263*7c478bd9Sstevel@tonic-gate 				sdp->sd_ref = REF_REL_NEED;
264*7c478bd9Sstevel@tonic-gate 				sdp->sd_flags |= FLG_SY_SPECSEC;
265*7c478bd9Sstevel@tonic-gate 				sdp->sd_flags1 |= FLG_SY1_GLOB;
266*7c478bd9Sstevel@tonic-gate 				sdp->sd_aux->sa_overndx = vdp->vd_ndx;
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 				/*
269*7c478bd9Sstevel@tonic-gate 				 * If the reference originated from a mapfile
270*7c478bd9Sstevel@tonic-gate 				 * insure we mark the symbol as used.
271*7c478bd9Sstevel@tonic-gate 				 */
272*7c478bd9Sstevel@tonic-gate 				if (sdp->sd_flags & FLG_SY_MAPREF)
273*7c478bd9Sstevel@tonic-gate 					sdp->sd_flags |= FLG_SY_MAPUSED;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 			} else if ((sdp->sd_flags & FLG_SY_SPECSEC) &&
276*7c478bd9Sstevel@tonic-gate 			    (sdp->sd_shndx != SHN_ABS) &&
277*7c478bd9Sstevel@tonic-gate 			    (sdp->sd_ref == REF_REL_NEED)) {
278*7c478bd9Sstevel@tonic-gate 				eprintf(ERR_WARNING, MSG_INTL(MSG_VER_DEFINED),
279*7c478bd9Sstevel@tonic-gate 				    name, sdp->sd_file->ifl_name);
280*7c478bd9Sstevel@tonic-gate 			}
281*7c478bd9Sstevel@tonic-gate 		} else {
282*7c478bd9Sstevel@tonic-gate 			/*
283*7c478bd9Sstevel@tonic-gate 			 * If the symbol does not exist create it.
284*7c478bd9Sstevel@tonic-gate 			 */
285*7c478bd9Sstevel@tonic-gate 			if ((sym = libld_calloc(sizeof (Sym), 1)) == 0)
286*7c478bd9Sstevel@tonic-gate 				return (S_ERROR);
287*7c478bd9Sstevel@tonic-gate 			sym->st_shndx = SHN_ABS;
288*7c478bd9Sstevel@tonic-gate 			sym->st_info = ELF_ST_INFO(bind, STT_OBJECT);
289*7c478bd9Sstevel@tonic-gate 			DBG_CALL(Dbg_ver_symbol(name));
290*7c478bd9Sstevel@tonic-gate 			if ((sdp = sym_enter(name, sym, vdp->vd_hash,
291*7c478bd9Sstevel@tonic-gate 			    vdp->vd_file, ofl, 0, SHN_ABS, FLG_SY_SPECSEC,
292*7c478bd9Sstevel@tonic-gate 			    FLG_SY1_GLOB, &where)) == (Sym_desc *)S_ERROR)
293*7c478bd9Sstevel@tonic-gate 				return (S_ERROR);
294*7c478bd9Sstevel@tonic-gate 			sdp->sd_ref = REF_REL_NEED;
295*7c478bd9Sstevel@tonic-gate 			sdp->sd_aux->sa_overndx = vdp->vd_ndx;
296*7c478bd9Sstevel@tonic-gate 		}
297*7c478bd9Sstevel@tonic-gate 	}
298*7c478bd9Sstevel@tonic-gate 	return (1);
299*7c478bd9Sstevel@tonic-gate }
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate /*
302*7c478bd9Sstevel@tonic-gate  * Dereference dependencies as a part of normalizing (allows recursion).
303*7c478bd9Sstevel@tonic-gate  */
304*7c478bd9Sstevel@tonic-gate void
305*7c478bd9Sstevel@tonic-gate vers_derefer(Ifl_desc *ifl, Ver_desc *vdp, int weak)
306*7c478bd9Sstevel@tonic-gate {
307*7c478bd9Sstevel@tonic-gate 	Listnode	*lnp;
308*7c478bd9Sstevel@tonic-gate 	Ver_desc	*_vdp;
309*7c478bd9Sstevel@tonic-gate 	Ver_index	*vip = &ifl->ifl_verndx[vdp->vd_ndx];
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	/*
312*7c478bd9Sstevel@tonic-gate 	 * If the head of the list was a weak then we only clear out
313*7c478bd9Sstevel@tonic-gate 	 * weak dependencies, but if the head of the list was 'strong'
314*7c478bd9Sstevel@tonic-gate 	 * we clear the REFER bit on all dependencies.
315*7c478bd9Sstevel@tonic-gate 	 */
316*7c478bd9Sstevel@tonic-gate 	if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak))
317*7c478bd9Sstevel@tonic-gate 		vip->vi_flags &= ~FLG_VER_REFER;
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&vdp->vd_deps, lnp, _vdp))
320*7c478bd9Sstevel@tonic-gate 		vers_derefer(ifl, _vdp, weak);
321*7c478bd9Sstevel@tonic-gate }
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate /*
324*7c478bd9Sstevel@tonic-gate  * If we need to record the versions of any needed dependencies traverse the
325*7c478bd9Sstevel@tonic-gate  * shared object dependency list and calculate what version needed entries are
326*7c478bd9Sstevel@tonic-gate  * required.
327*7c478bd9Sstevel@tonic-gate  */
328*7c478bd9Sstevel@tonic-gate uintptr_t
329*7c478bd9Sstevel@tonic-gate vers_check_need(Ofl_desc *ofl)
330*7c478bd9Sstevel@tonic-gate {
331*7c478bd9Sstevel@tonic-gate 	Listnode	*lnp1;
332*7c478bd9Sstevel@tonic-gate 	Ifl_desc	*ifl;
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	/*
335*7c478bd9Sstevel@tonic-gate 	 * Traverse the shared object list looking for dependencies.
336*7c478bd9Sstevel@tonic-gate 	 */
337*7c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ofl->ofl_sos, lnp1, ifl)) {
338*7c478bd9Sstevel@tonic-gate 		Listnode	*lnp2;
339*7c478bd9Sstevel@tonic-gate 		Ver_index	*vip;
340*7c478bd9Sstevel@tonic-gate 		Ver_desc	*vdp;
341*7c478bd9Sstevel@tonic-gate 		Sdf_desc	*sdf = ifl->ifl_sdfdesc;
342*7c478bd9Sstevel@tonic-gate 		Byte		cnt, need;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 		if (!(ifl->ifl_flags & FLG_IF_NEEDED))
345*7c478bd9Sstevel@tonic-gate 			continue;
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 		if (ifl->ifl_vercnt <= VER_NDX_GLOBAL)
348*7c478bd9Sstevel@tonic-gate 			continue;
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 		/*
351*7c478bd9Sstevel@tonic-gate 		 * If version needed definitions were specified in
352*7c478bd9Sstevel@tonic-gate 		 * a mapfile ($SPECVERS=) then record those definitions
353*7c478bd9Sstevel@tonic-gate 		 */
354*7c478bd9Sstevel@tonic-gate 		if (sdf && (sdf->sdf_flags & FLG_SDF_SPECVER)) {
355*7c478bd9Sstevel@tonic-gate 			Sdv_desc	*sdv;
356*7c478bd9Sstevel@tonic-gate 			for (LIST_TRAVERSE(&sdf->sdf_verneed, lnp2,
357*7c478bd9Sstevel@tonic-gate 			    sdv)) {
358*7c478bd9Sstevel@tonic-gate 				ofl->ofl_verneedsz += sizeof (Vernaux);
359*7c478bd9Sstevel@tonic-gate 				if (st_insert(ofl->ofl_dynstrtab,
360*7c478bd9Sstevel@tonic-gate 				    sdv->sdv_name) == -1)
361*7c478bd9Sstevel@tonic-gate 					return (S_ERROR);
362*7c478bd9Sstevel@tonic-gate 			}
363*7c478bd9Sstevel@tonic-gate 			ifl->ifl_flags |= FLG_IF_VERNEED;
364*7c478bd9Sstevel@tonic-gate 			ofl->ofl_verneedsz += sizeof (Verneed);
365*7c478bd9Sstevel@tonic-gate 			if (st_insert(ofl->ofl_dynstrtab,
366*7c478bd9Sstevel@tonic-gate 			    ifl->ifl_soname) == -1)
367*7c478bd9Sstevel@tonic-gate 				return (S_ERROR);
368*7c478bd9Sstevel@tonic-gate 			continue;
369*7c478bd9Sstevel@tonic-gate 		}
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 		/*
372*7c478bd9Sstevel@tonic-gate 		 * Scan the version index list and if any weak version
373*7c478bd9Sstevel@tonic-gate 		 * definition has been referenced by the user promote the
374*7c478bd9Sstevel@tonic-gate 		 * dependency to be non-weak.  Weak version dependencies do not
375*7c478bd9Sstevel@tonic-gate 		 * cause fatal errors from the runtime linker, non-weak
376*7c478bd9Sstevel@tonic-gate 		 * dependencies do.
377*7c478bd9Sstevel@tonic-gate 		 */
378*7c478bd9Sstevel@tonic-gate 		for (need = 0, cnt = 0; cnt <= ifl->ifl_vercnt; cnt++) {
379*7c478bd9Sstevel@tonic-gate 			vip = &ifl->ifl_verndx[cnt];
380*7c478bd9Sstevel@tonic-gate 			vdp = vip->vi_desc;
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 			if ((vip->vi_flags & (FLG_VER_REFER | VER_FLG_WEAK)) ==
383*7c478bd9Sstevel@tonic-gate 			    (FLG_VER_REFER | VER_FLG_WEAK))
384*7c478bd9Sstevel@tonic-gate 				vdp->vd_flags &= ~VER_FLG_WEAK;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 			/*
387*7c478bd9Sstevel@tonic-gate 			 * Mark any weak reference as referred to so as to
388*7c478bd9Sstevel@tonic-gate 			 * simplify normalization and later version dependency
389*7c478bd9Sstevel@tonic-gate 			 * manipulation.
390*7c478bd9Sstevel@tonic-gate 			 */
391*7c478bd9Sstevel@tonic-gate 			if (vip->vi_flags & VER_FLG_WEAK)
392*7c478bd9Sstevel@tonic-gate 				vip->vi_flags |= FLG_VER_REFER;
393*7c478bd9Sstevel@tonic-gate 		}
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 		/*
396*7c478bd9Sstevel@tonic-gate 		 * Scan the version dependency list to normalize the referenced
397*7c478bd9Sstevel@tonic-gate 		 * dependencies.  Any needed version that is inherited by
398*7c478bd9Sstevel@tonic-gate 		 * another like version is derefereced as it is not necessary
399*7c478bd9Sstevel@tonic-gate 		 * to make this part of the version dependencies.
400*7c478bd9Sstevel@tonic-gate 		 */
401*7c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&ifl->ifl_verdesc, lnp2, vdp)) {
402*7c478bd9Sstevel@tonic-gate 			Listnode	*lnp3;
403*7c478bd9Sstevel@tonic-gate 			Ver_desc	*_vdp;
404*7c478bd9Sstevel@tonic-gate 			int		type;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 			vip = &ifl->ifl_verndx[vdp->vd_ndx];
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 			if (!(vip->vi_flags & FLG_VER_REFER))
409*7c478bd9Sstevel@tonic-gate 				continue;
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 			type = vdp->vd_flags & VER_FLG_WEAK;
412*7c478bd9Sstevel@tonic-gate 			for (LIST_TRAVERSE(&vdp->vd_deps, lnp3, _vdp))
413*7c478bd9Sstevel@tonic-gate 				vers_derefer(ifl, _vdp, type);
414*7c478bd9Sstevel@tonic-gate 		}
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 		/*
417*7c478bd9Sstevel@tonic-gate 		 * Finally, determine how many of the version dependencies need
418*7c478bd9Sstevel@tonic-gate 		 * to be recorded.
419*7c478bd9Sstevel@tonic-gate 		 */
420*7c478bd9Sstevel@tonic-gate 		for (need = 0, cnt = 0; cnt <= ifl->ifl_vercnt; cnt++) {
421*7c478bd9Sstevel@tonic-gate 			vip = &ifl->ifl_verndx[cnt];
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 			/*
424*7c478bd9Sstevel@tonic-gate 			 * If a version has been referenced then record it as a
425*7c478bd9Sstevel@tonic-gate 			 * version dependency.
426*7c478bd9Sstevel@tonic-gate 			 */
427*7c478bd9Sstevel@tonic-gate 			if (vip->vi_flags & FLG_VER_REFER) {
428*7c478bd9Sstevel@tonic-gate 				ofl->ofl_verneedsz += sizeof (Vernaux);
429*7c478bd9Sstevel@tonic-gate 				if (st_insert(ofl->ofl_dynstrtab,
430*7c478bd9Sstevel@tonic-gate 				    vip->vi_name) == -1)
431*7c478bd9Sstevel@tonic-gate 					return (S_ERROR);
432*7c478bd9Sstevel@tonic-gate 				need++;
433*7c478bd9Sstevel@tonic-gate 			}
434*7c478bd9Sstevel@tonic-gate 		}
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 		if (need) {
437*7c478bd9Sstevel@tonic-gate 			ifl->ifl_flags |= FLG_IF_VERNEED;
438*7c478bd9Sstevel@tonic-gate 			ofl->ofl_verneedsz += sizeof (Verneed);
439*7c478bd9Sstevel@tonic-gate 			if (st_insert(ofl->ofl_dynstrtab,
440*7c478bd9Sstevel@tonic-gate 			    ifl->ifl_soname) == -1)
441*7c478bd9Sstevel@tonic-gate 				return (S_ERROR);
442*7c478bd9Sstevel@tonic-gate 		}
443*7c478bd9Sstevel@tonic-gate 	}
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	/*
446*7c478bd9Sstevel@tonic-gate 	 * If no version needed information is required unset the output file
447*7c478bd9Sstevel@tonic-gate 	 * flag.
448*7c478bd9Sstevel@tonic-gate 	 */
449*7c478bd9Sstevel@tonic-gate 	if (ofl->ofl_verneedsz == 0)
450*7c478bd9Sstevel@tonic-gate 		ofl->ofl_flags &= ~FLG_OF_VERNEED;
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 	return (1);
453*7c478bd9Sstevel@tonic-gate }
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate /*
456*7c478bd9Sstevel@tonic-gate  * Indicate dependency selection (allows recursion).
457*7c478bd9Sstevel@tonic-gate  */
458*7c478bd9Sstevel@tonic-gate void
459*7c478bd9Sstevel@tonic-gate vers_select(Ifl_desc *ifl, Ver_desc *vdp, const char *ref)
460*7c478bd9Sstevel@tonic-gate {
461*7c478bd9Sstevel@tonic-gate 	Listnode	*lnp;
462*7c478bd9Sstevel@tonic-gate 	Ver_desc	*_vdp;
463*7c478bd9Sstevel@tonic-gate 	Ver_index	*vip = &ifl->ifl_verndx[vdp->vd_ndx];
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	vip->vi_flags |= FLG_VER_AVAIL;
466*7c478bd9Sstevel@tonic-gate 	DBG_CALL(Dbg_ver_avail_entry(vip, ref));
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&vdp->vd_deps, lnp, _vdp))
469*7c478bd9Sstevel@tonic-gate 		vers_select(ifl, _vdp, ref);
470*7c478bd9Sstevel@tonic-gate }
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate Ver_index *
473*7c478bd9Sstevel@tonic-gate vers_index(Ifl_desc *ifl, int avail)
474*7c478bd9Sstevel@tonic-gate {
475*7c478bd9Sstevel@tonic-gate 	Listnode	*lnp;
476*7c478bd9Sstevel@tonic-gate 	Ver_desc	*vdp;
477*7c478bd9Sstevel@tonic-gate 	Ver_index	*vip;
478*7c478bd9Sstevel@tonic-gate 	Sdf_desc	*sdf = ifl->ifl_sdfdesc;
479*7c478bd9Sstevel@tonic-gate 	Word		count = ifl->ifl_vercnt;
480*7c478bd9Sstevel@tonic-gate 	Sdv_desc	*sdv;
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	/*
483*7c478bd9Sstevel@tonic-gate 	 * Allocate an index array large enough to hold all of the files
484*7c478bd9Sstevel@tonic-gate 	 * version descriptors.
485*7c478bd9Sstevel@tonic-gate 	 */
486*7c478bd9Sstevel@tonic-gate 	if ((vip = libld_calloc(sizeof (Ver_index),
487*7c478bd9Sstevel@tonic-gate 	    (count + 1))) == 0)
488*7c478bd9Sstevel@tonic-gate 		return ((Ver_index *)S_ERROR);
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ifl->ifl_verdesc, lnp, vdp)) {
491*7c478bd9Sstevel@tonic-gate 		int		ndx = vdp->vd_ndx;
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 		vip[ndx].vi_name = vdp->vd_name;
494*7c478bd9Sstevel@tonic-gate 		vip[ndx].vi_desc = vdp;
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 		/*
497*7c478bd9Sstevel@tonic-gate 		 * Any relocatable object versions, and the `base' version are
498*7c478bd9Sstevel@tonic-gate 		 * always available.
499*7c478bd9Sstevel@tonic-gate 		 */
500*7c478bd9Sstevel@tonic-gate 		if (avail || (vdp->vd_flags & VER_FLG_BASE))
501*7c478bd9Sstevel@tonic-gate 			vip[ndx].vi_flags |= FLG_VER_AVAIL;
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 		/*
504*7c478bd9Sstevel@tonic-gate 		 * If this is a weak version mark it as such.  Weak versions
505*7c478bd9Sstevel@tonic-gate 		 * are always dragged into any version dependencies created,
506*7c478bd9Sstevel@tonic-gate 		 * and if a weak version is referenced it will be promoted to
507*7c478bd9Sstevel@tonic-gate 		 * a non-weak version dependency.
508*7c478bd9Sstevel@tonic-gate 		 */
509*7c478bd9Sstevel@tonic-gate 		if (vdp->vd_flags & VER_FLG_WEAK)
510*7c478bd9Sstevel@tonic-gate 			vip[ndx].vi_flags |= VER_FLG_WEAK;
511*7c478bd9Sstevel@tonic-gate 		/*
512*7c478bd9Sstevel@tonic-gate 		 * If this version is mentioned in a mapfile
513*7c478bd9Sstevel@tonic-gate 		 * $ADDVERS syntax then add a FLG_IF_NEEDED flag now
514*7c478bd9Sstevel@tonic-gate 		 */
515*7c478bd9Sstevel@tonic-gate 		if (sdf && (sdf->sdf_flags & FLG_SDF_ADDVER)) {
516*7c478bd9Sstevel@tonic-gate 			Listnode *	lnp2;
517*7c478bd9Sstevel@tonic-gate 			for (LIST_TRAVERSE(&sdf->sdf_verneed, lnp2, sdv)) {
518*7c478bd9Sstevel@tonic-gate 				if (strcmp(vip[ndx].vi_name,
519*7c478bd9Sstevel@tonic-gate 				    sdv->sdv_name) == 0) {
520*7c478bd9Sstevel@tonic-gate 					vip[ndx].vi_flags |= FLG_VER_REFER;
521*7c478bd9Sstevel@tonic-gate 					sdv->sdv_flags |= FLG_SDV_MATCHED;
522*7c478bd9Sstevel@tonic-gate 					break;
523*7c478bd9Sstevel@tonic-gate 				}
524*7c478bd9Sstevel@tonic-gate 			}
525*7c478bd9Sstevel@tonic-gate 		}
526*7c478bd9Sstevel@tonic-gate 	}
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	/*
529*7c478bd9Sstevel@tonic-gate 	 * if $ADDVER was specified for this object verify that
530*7c478bd9Sstevel@tonic-gate 	 * all of it's dependent upon versions were refered to.
531*7c478bd9Sstevel@tonic-gate 	 */
532*7c478bd9Sstevel@tonic-gate 	if (sdf && (sdf->sdf_flags & FLG_SDF_ADDVER)) {
533*7c478bd9Sstevel@tonic-gate 		int	fail = 0;
534*7c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&sdf->sdf_verneed, lnp, sdv)) {
535*7c478bd9Sstevel@tonic-gate 			if (!(sdv->sdv_flags & FLG_SDV_MATCHED)) {
536*7c478bd9Sstevel@tonic-gate 				if (fail == 0) {
537*7c478bd9Sstevel@tonic-gate 					fail++;
538*7c478bd9Sstevel@tonic-gate 					eprintf(ERR_NONE,
539*7c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_VER_ADDVERS),
540*7c478bd9Sstevel@tonic-gate 					    sdf->sdf_rfile, sdf->sdf_name);
541*7c478bd9Sstevel@tonic-gate 				}
542*7c478bd9Sstevel@tonic-gate 				eprintf(ERR_NONE, MSG_INTL(MSG_VER_ADDVER),
543*7c478bd9Sstevel@tonic-gate 				    sdv->sdv_name);
544*7c478bd9Sstevel@tonic-gate 			}
545*7c478bd9Sstevel@tonic-gate 		}
546*7c478bd9Sstevel@tonic-gate 		if (fail)
547*7c478bd9Sstevel@tonic-gate 			return ((Ver_index *)S_ERROR);
548*7c478bd9Sstevel@tonic-gate 	}
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	return (vip);
551*7c478bd9Sstevel@tonic-gate }
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate /*
554*7c478bd9Sstevel@tonic-gate  * Process a version symbol index section.
555*7c478bd9Sstevel@tonic-gate  */
556*7c478bd9Sstevel@tonic-gate int
557*7c478bd9Sstevel@tonic-gate vers_sym_process(Is_desc *isp, Ifl_desc *ifl)
558*7c478bd9Sstevel@tonic-gate {
559*7c478bd9Sstevel@tonic-gate 	Shdr	*symshdr;
560*7c478bd9Sstevel@tonic-gate 	Shdr	*vershdr = isp->is_shdr;
561*7c478bd9Sstevel@tonic-gate 	/*
562*7c478bd9Sstevel@tonic-gate 	 * Verify that the versym is the same size as the
563*7c478bd9Sstevel@tonic-gate 	 * linked symbol table.  If these two get out of sync
564*7c478bd9Sstevel@tonic-gate 	 * the file is considered corrupted.
565*7c478bd9Sstevel@tonic-gate 	 */
566*7c478bd9Sstevel@tonic-gate 	symshdr = ifl->ifl_isdesc[vershdr->sh_link]->is_shdr;
567*7c478bd9Sstevel@tonic-gate 	if ((symshdr->sh_size / symshdr->sh_entsize) != (vershdr->sh_size /
568*7c478bd9Sstevel@tonic-gate 	    vershdr->sh_entsize)) {
569*7c478bd9Sstevel@tonic-gate 		eprintf(ERR_WARNING, MSG_INTL(MSG_ELF_VERSYM), ifl->ifl_name,
570*7c478bd9Sstevel@tonic-gate 			isp->is_name,
571*7c478bd9Sstevel@tonic-gate 			EC_WORD(vershdr->sh_size / vershdr->sh_entsize),
572*7c478bd9Sstevel@tonic-gate 			ifl->ifl_isdesc[vershdr->sh_link]->is_name,
573*7c478bd9Sstevel@tonic-gate 			EC_WORD(symshdr->sh_size / symshdr->sh_entsize));
574*7c478bd9Sstevel@tonic-gate 		return (1);
575*7c478bd9Sstevel@tonic-gate 	}
576*7c478bd9Sstevel@tonic-gate 	ifl->ifl_versym = (Versym *)isp->is_indata->d_buf;
577*7c478bd9Sstevel@tonic-gate 	return (1);
578*7c478bd9Sstevel@tonic-gate }
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate /*
581*7c478bd9Sstevel@tonic-gate  * Process a version definition section from an input file.  A list of version
582*7c478bd9Sstevel@tonic-gate  * descriptors is created and associated with the input files descriptor.  If
583*7c478bd9Sstevel@tonic-gate  * this is a shared object these descriptors will be used to indicate the
584*7c478bd9Sstevel@tonic-gate  * availability of each version.  If this is a relocatable object then these
585*7c478bd9Sstevel@tonic-gate  * descriptors will be promoted (concatenated) to the output files image.
586*7c478bd9Sstevel@tonic-gate  */
587*7c478bd9Sstevel@tonic-gate uintptr_t
588*7c478bd9Sstevel@tonic-gate vers_def_process(Is_desc *isp, Ifl_desc *ifl, Ofl_desc *ofl)
589*7c478bd9Sstevel@tonic-gate {
590*7c478bd9Sstevel@tonic-gate 	const char	*str, *file = ifl->ifl_name;
591*7c478bd9Sstevel@tonic-gate 	Sdf_desc	*sdf = ifl->ifl_sdfdesc;
592*7c478bd9Sstevel@tonic-gate 	Sdv_desc	*sdv;
593*7c478bd9Sstevel@tonic-gate 	Word		num, _num;
594*7c478bd9Sstevel@tonic-gate 	Verdef		*vdf;
595*7c478bd9Sstevel@tonic-gate 	int		relobj;
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 	/*
598*7c478bd9Sstevel@tonic-gate 	 * If there is no version section then simply indicate that all version
599*7c478bd9Sstevel@tonic-gate 	 * definitions asked for do not exist.
600*7c478bd9Sstevel@tonic-gate 	 */
601*7c478bd9Sstevel@tonic-gate 	if (isp == 0) {
602*7c478bd9Sstevel@tonic-gate 		Listnode	*lnp;
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&sdf->sdf_vers, lnp, sdv)) {
605*7c478bd9Sstevel@tonic-gate 			eprintf(ERR_FATAL, MSG_INTL(MSG_VER_NOEXIST),
606*7c478bd9Sstevel@tonic-gate 			    ifl->ifl_name, sdv->sdv_name, sdv->sdv_ref);
607*7c478bd9Sstevel@tonic-gate 			ofl->ofl_flags |= FLG_OF_FATAL;
608*7c478bd9Sstevel@tonic-gate 		}
609*7c478bd9Sstevel@tonic-gate 		return (0);
610*7c478bd9Sstevel@tonic-gate 	}
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	vdf = (Verdef *)isp->is_indata->d_buf;
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	/*
615*7c478bd9Sstevel@tonic-gate 	 * Verify the version revision.  We only check the first version
616*7c478bd9Sstevel@tonic-gate 	 * structure as it is assumed all other version structures in this
617*7c478bd9Sstevel@tonic-gate 	 * data section will be of the same revision.
618*7c478bd9Sstevel@tonic-gate 	 */
619*7c478bd9Sstevel@tonic-gate 	if (vdf->vd_version > VER_DEF_CURRENT)
620*7c478bd9Sstevel@tonic-gate 		(void) eprintf(ERR_WARNING, MSG_INTL(MSG_VER_HIGHER),
621*7c478bd9Sstevel@tonic-gate 		    ifl->ifl_name, vdf->vd_version, VER_DEF_CURRENT);
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	num = isp->is_shdr->sh_info;
625*7c478bd9Sstevel@tonic-gate 	str = (char *)ifl->ifl_isdesc[isp->is_shdr->sh_link]->is_indata->d_buf;
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate 	if (ifl->ifl_ehdr->e_type == ET_REL)
628*7c478bd9Sstevel@tonic-gate 		relobj = 1;
629*7c478bd9Sstevel@tonic-gate 	else
630*7c478bd9Sstevel@tonic-gate 		relobj = 0;
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	DBG_CALL(Dbg_ver_def_title(file));
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	/*
635*7c478bd9Sstevel@tonic-gate 	 * Loop through the version information setting up a version descriptor
636*7c478bd9Sstevel@tonic-gate 	 * for each version definition.
637*7c478bd9Sstevel@tonic-gate 	 */
638*7c478bd9Sstevel@tonic-gate 	for (_num = 1; _num <= num; _num++,
639*7c478bd9Sstevel@tonic-gate 	    vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) {
640*7c478bd9Sstevel@tonic-gate 		const char	*name;
641*7c478bd9Sstevel@tonic-gate 		Ver_desc	*ivdp, *ovdp = 0;
642*7c478bd9Sstevel@tonic-gate 		Word		hash;
643*7c478bd9Sstevel@tonic-gate 		Half 		cnt = vdf->vd_cnt;
644*7c478bd9Sstevel@tonic-gate 		Half		ndx = vdf->vd_ndx;
645*7c478bd9Sstevel@tonic-gate 		Verdaux		*vdap = (Verdaux *)((uintptr_t)vdf +
646*7c478bd9Sstevel@tonic-gate 				    vdf->vd_aux);
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 		/*
649*7c478bd9Sstevel@tonic-gate 		 * Keep track of the largest index for use in creating a
650*7c478bd9Sstevel@tonic-gate 		 * version index array later, and create a version descriptor.
651*7c478bd9Sstevel@tonic-gate 		 */
652*7c478bd9Sstevel@tonic-gate 		if (ndx > ifl->ifl_vercnt)
653*7c478bd9Sstevel@tonic-gate 			ifl->ifl_vercnt = ndx;
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 		name = (char *)(str + vdap->vda_name);
656*7c478bd9Sstevel@tonic-gate 		/* LINTED */
657*7c478bd9Sstevel@tonic-gate 		hash = (Word)elf_hash(name);
658*7c478bd9Sstevel@tonic-gate 		if ((ivdp = vers_find(name, hash, &ifl->ifl_verdesc)) == 0) {
659*7c478bd9Sstevel@tonic-gate 			if ((ivdp = vers_desc(name, hash,
660*7c478bd9Sstevel@tonic-gate 			    &ifl->ifl_verdesc)) == (Ver_desc *)S_ERROR)
661*7c478bd9Sstevel@tonic-gate 				return (S_ERROR);
662*7c478bd9Sstevel@tonic-gate 		}
663*7c478bd9Sstevel@tonic-gate 		ivdp->vd_ndx = ndx;
664*7c478bd9Sstevel@tonic-gate 		ivdp->vd_file = ifl;
665*7c478bd9Sstevel@tonic-gate 		ivdp->vd_flags = vdf->vd_flags;
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 		/*
668*7c478bd9Sstevel@tonic-gate 		 * If we're processing a relocatable object then this version
669*7c478bd9Sstevel@tonic-gate 		 * definition needs to be propagated to the output file.
670*7c478bd9Sstevel@tonic-gate 		 * Generate a new output file version and associated this input
671*7c478bd9Sstevel@tonic-gate 		 * version to it.  During symbol processing the version index of
672*7c478bd9Sstevel@tonic-gate 		 * the symbol will be promoted from the input file to the output
673*7c478bd9Sstevel@tonic-gate 		 * files version definition.
674*7c478bd9Sstevel@tonic-gate 		 */
675*7c478bd9Sstevel@tonic-gate 		if (relobj) {
676*7c478bd9Sstevel@tonic-gate 			if (!(ofl->ofl_flags & FLG_OF_RELOBJ))
677*7c478bd9Sstevel@tonic-gate 				ofl->ofl_flags |= FLG_OF_PROCRED;
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 			if ((ivdp->vd_flags & VER_FLG_BASE) == 0) {
680*7c478bd9Sstevel@tonic-gate 				/*
681*7c478bd9Sstevel@tonic-gate 				 * If no version descriptors have yet been set
682*7c478bd9Sstevel@tonic-gate 				 * up, initialize a base version to represent
683*7c478bd9Sstevel@tonic-gate 				 * the output file itself.  This `base' version
684*7c478bd9Sstevel@tonic-gate 				 * catches any internally generated symbols
685*7c478bd9Sstevel@tonic-gate 				 * (_end, _etext, etc.) and
686*7c478bd9Sstevel@tonic-gate 				 * serves to initialize the output version
687*7c478bd9Sstevel@tonic-gate 				 * descriptor count.
688*7c478bd9Sstevel@tonic-gate 				 */
689*7c478bd9Sstevel@tonic-gate 				if (ofl->ofl_vercnt == 0) {
690*7c478bd9Sstevel@tonic-gate 					if (vers_base(ofl) ==
691*7c478bd9Sstevel@tonic-gate 					    (Ver_desc *)S_ERROR)
692*7c478bd9Sstevel@tonic-gate 						return (S_ERROR);
693*7c478bd9Sstevel@tonic-gate 				}
694*7c478bd9Sstevel@tonic-gate 				ofl->ofl_flags |= FLG_OF_VERDEF;
695*7c478bd9Sstevel@tonic-gate 				if ((ovdp = vers_find(name, hash,
696*7c478bd9Sstevel@tonic-gate 				    &ofl->ofl_verdesc)) == 0) {
697*7c478bd9Sstevel@tonic-gate 					if ((ovdp = vers_desc(name, hash,
698*7c478bd9Sstevel@tonic-gate 					    &ofl->ofl_verdesc)) ==
699*7c478bd9Sstevel@tonic-gate 					    (Ver_desc *)S_ERROR)
700*7c478bd9Sstevel@tonic-gate 						return (S_ERROR);
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 					/* LINTED */
703*7c478bd9Sstevel@tonic-gate 					ovdp->vd_ndx = (Half)++ofl->ofl_vercnt;
704*7c478bd9Sstevel@tonic-gate 					ovdp->vd_file = ifl;
705*7c478bd9Sstevel@tonic-gate 					ovdp->vd_flags = vdf->vd_flags;
706*7c478bd9Sstevel@tonic-gate 				}
707*7c478bd9Sstevel@tonic-gate 			}
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 			/*
710*7c478bd9Sstevel@tonic-gate 			 * Maintain the association between the input version
711*7c478bd9Sstevel@tonic-gate 			 * descriptor and the output version descriptor so that
712*7c478bd9Sstevel@tonic-gate 			 * an associated symbols will be assigned to the
713*7c478bd9Sstevel@tonic-gate 			 * correct version.
714*7c478bd9Sstevel@tonic-gate 			 */
715*7c478bd9Sstevel@tonic-gate 			ivdp->vd_ref = ovdp;
716*7c478bd9Sstevel@tonic-gate 		}
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 		/*
719*7c478bd9Sstevel@tonic-gate 		 * Process any dependencies this version may have.
720*7c478bd9Sstevel@tonic-gate 		 */
721*7c478bd9Sstevel@tonic-gate 		vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next);
722*7c478bd9Sstevel@tonic-gate 		for (cnt--; cnt; cnt--,
723*7c478bd9Sstevel@tonic-gate 		    vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next)) {
724*7c478bd9Sstevel@tonic-gate 			Ver_desc	*_ivdp;
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 			name = (char *)(str + vdap->vda_name);
727*7c478bd9Sstevel@tonic-gate 			/* LINTED */
728*7c478bd9Sstevel@tonic-gate 			hash = (Word)elf_hash(name);
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate 			if ((_ivdp = vers_find(name, hash,
731*7c478bd9Sstevel@tonic-gate 			    &ifl->ifl_verdesc)) == 0) {
732*7c478bd9Sstevel@tonic-gate 				if ((_ivdp = vers_desc(name, hash,
733*7c478bd9Sstevel@tonic-gate 				    &ifl->ifl_verdesc)) ==
734*7c478bd9Sstevel@tonic-gate 				    (Ver_desc *)S_ERROR)
735*7c478bd9Sstevel@tonic-gate 					return (S_ERROR);
736*7c478bd9Sstevel@tonic-gate 			}
737*7c478bd9Sstevel@tonic-gate 			if (list_appendc(&ivdp->vd_deps, _ivdp) == 0)
738*7c478bd9Sstevel@tonic-gate 				return (S_ERROR);
739*7c478bd9Sstevel@tonic-gate 		}
740*7c478bd9Sstevel@tonic-gate 		DBG_CALL(Dbg_ver_desc_entry(ivdp));
741*7c478bd9Sstevel@tonic-gate 	}
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	/*
744*7c478bd9Sstevel@tonic-gate 	 * Now that we know the total number of version definitions for this
745*7c478bd9Sstevel@tonic-gate 	 * file, build an index array for fast access when processing symbols.
746*7c478bd9Sstevel@tonic-gate 	 */
747*7c478bd9Sstevel@tonic-gate 	if ((ifl->ifl_verndx = vers_index(ifl, relobj)) == (Ver_index *)S_ERROR)
748*7c478bd9Sstevel@tonic-gate 		return (S_ERROR);
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	if (relobj)
751*7c478bd9Sstevel@tonic-gate 		return (1);
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 	/*
754*7c478bd9Sstevel@tonic-gate 	 * If this object has version control definitions against it then these
755*7c478bd9Sstevel@tonic-gate 	 * must be processed so as to select those version definitions to which
756*7c478bd9Sstevel@tonic-gate 	 * symbol bindings can occur.  Otherwise simply mark all versions as
757*7c478bd9Sstevel@tonic-gate 	 * available.
758*7c478bd9Sstevel@tonic-gate 	 */
759*7c478bd9Sstevel@tonic-gate 	DBG_CALL(Dbg_ver_avail_title(file));
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 	if (sdf && (sdf->sdf_flags & FLG_SDF_SELECT)) {
762*7c478bd9Sstevel@tonic-gate 		Listnode	*lnp1;
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&sdf->sdf_vers, lnp1, sdv)) {
765*7c478bd9Sstevel@tonic-gate 			Listnode	*lnp2;
766*7c478bd9Sstevel@tonic-gate 			Ver_desc	*vdp;
767*7c478bd9Sstevel@tonic-gate 			int		found = 0;
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 			for (LIST_TRAVERSE(&ifl->ifl_verdesc, lnp2, vdp)) {
770*7c478bd9Sstevel@tonic-gate 				if (strcmp(sdv->sdv_name, vdp->vd_name) == 0) {
771*7c478bd9Sstevel@tonic-gate 					found++;
772*7c478bd9Sstevel@tonic-gate 					break;
773*7c478bd9Sstevel@tonic-gate 				}
774*7c478bd9Sstevel@tonic-gate 			}
775*7c478bd9Sstevel@tonic-gate 			if (found)
776*7c478bd9Sstevel@tonic-gate 				vers_select(ifl, vdp, sdv->sdv_ref);
777*7c478bd9Sstevel@tonic-gate 			else {
778*7c478bd9Sstevel@tonic-gate 				eprintf(ERR_FATAL, MSG_INTL(MSG_VER_NOEXIST),
779*7c478bd9Sstevel@tonic-gate 				    ifl->ifl_name, sdv->sdv_name, sdv->sdv_ref);
780*7c478bd9Sstevel@tonic-gate 				ofl->ofl_flags |= FLG_OF_FATAL;
781*7c478bd9Sstevel@tonic-gate 			}
782*7c478bd9Sstevel@tonic-gate 		}
783*7c478bd9Sstevel@tonic-gate 	} else {
784*7c478bd9Sstevel@tonic-gate 		Ver_index	*vip;
785*7c478bd9Sstevel@tonic-gate 		int		cnt;
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 		for (cnt = VER_NDX_GLOBAL; cnt <= ifl->ifl_vercnt; cnt++) {
788*7c478bd9Sstevel@tonic-gate 			vip = &ifl->ifl_verndx[cnt];
789*7c478bd9Sstevel@tonic-gate 			vip->vi_flags |= FLG_VER_AVAIL;
790*7c478bd9Sstevel@tonic-gate 			DBG_CALL(Dbg_ver_avail_entry(vip, 0));
791*7c478bd9Sstevel@tonic-gate 		}
792*7c478bd9Sstevel@tonic-gate 	}
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	/*
795*7c478bd9Sstevel@tonic-gate 	 * If this is an explict dependency indicate that this file is a
796*7c478bd9Sstevel@tonic-gate 	 * candidate for requiring version needed information to be recorded in
797*7c478bd9Sstevel@tonic-gate 	 * the image we're creating.
798*7c478bd9Sstevel@tonic-gate 	 */
799*7c478bd9Sstevel@tonic-gate 	if (ifl->ifl_flags & FLG_IF_NEEDED)
800*7c478bd9Sstevel@tonic-gate 		ofl->ofl_flags |= FLG_OF_VERNEED;
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	return (1);
803*7c478bd9Sstevel@tonic-gate }
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate /*
806*7c478bd9Sstevel@tonic-gate  * Process a version needed section.
807*7c478bd9Sstevel@tonic-gate  */
808*7c478bd9Sstevel@tonic-gate uintptr_t
809*7c478bd9Sstevel@tonic-gate vers_need_process(Is_desc *isp, Ifl_desc *ifl, Ofl_desc *ofl)
810*7c478bd9Sstevel@tonic-gate {
811*7c478bd9Sstevel@tonic-gate 	const char	*str, *file = ifl->ifl_name;
812*7c478bd9Sstevel@tonic-gate 	Word		num, _num;
813*7c478bd9Sstevel@tonic-gate 	Verneed		*vnd;
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 	vnd = (Verneed *)isp->is_indata->d_buf;
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 	/*
818*7c478bd9Sstevel@tonic-gate 	 * Verify the version revision.  We only check the first version
819*7c478bd9Sstevel@tonic-gate 	 * structure as it is assumed all other version structures in this
820*7c478bd9Sstevel@tonic-gate 	 * data section will be of the same revision.
821*7c478bd9Sstevel@tonic-gate 	 */
822*7c478bd9Sstevel@tonic-gate 	if (vnd->vn_version > VER_DEF_CURRENT)
823*7c478bd9Sstevel@tonic-gate 		(void) eprintf(ERR_WARNING, MSG_INTL(MSG_VER_HIGHER),
824*7c478bd9Sstevel@tonic-gate 		    ifl->ifl_name, vnd->vn_version, VER_DEF_CURRENT);
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 	num = isp->is_shdr->sh_info;
828*7c478bd9Sstevel@tonic-gate 	str = (char *)ifl->ifl_isdesc[isp->is_shdr->sh_link]->is_indata->d_buf;
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 	DBG_CALL(Dbg_ver_need_title(file));
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	/*
833*7c478bd9Sstevel@tonic-gate 	 * Loop through the version information setting up a version descriptor
834*7c478bd9Sstevel@tonic-gate 	 * for each version definition.
835*7c478bd9Sstevel@tonic-gate 	 */
836*7c478bd9Sstevel@tonic-gate 	for (_num = 1; _num <= num; _num++,
837*7c478bd9Sstevel@tonic-gate 	    vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
838*7c478bd9Sstevel@tonic-gate 		Sdf_desc	*sdf;
839*7c478bd9Sstevel@tonic-gate 		Sdv_desc	*sdv;
840*7c478bd9Sstevel@tonic-gate 		const char	*name;
841*7c478bd9Sstevel@tonic-gate 		Half		cnt = vnd->vn_cnt;
842*7c478bd9Sstevel@tonic-gate 		Vernaux		*vnap = (Vernaux *)((uintptr_t)vnd +
843*7c478bd9Sstevel@tonic-gate 				    vnd->vn_aux);
844*7c478bd9Sstevel@tonic-gate 		Half		_cnt;
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 		name = (char *)(str + vnd->vn_file);
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 		/*
849*7c478bd9Sstevel@tonic-gate 		 * Set up a shared object descriptor and add to it the necessary
850*7c478bd9Sstevel@tonic-gate 		 * needed versions.  This information may also have been added
851*7c478bd9Sstevel@tonic-gate 		 * by a mapfile (see map_dash()).
852*7c478bd9Sstevel@tonic-gate 		 */
853*7c478bd9Sstevel@tonic-gate 		if ((sdf = sdf_find(name, &ofl->ofl_soneed)) == 0) {
854*7c478bd9Sstevel@tonic-gate 			if ((sdf = sdf_add(name, &ofl->ofl_soneed)) ==
855*7c478bd9Sstevel@tonic-gate 			    (Sdf_desc *)S_ERROR)
856*7c478bd9Sstevel@tonic-gate 				return (S_ERROR);
857*7c478bd9Sstevel@tonic-gate 			sdf->sdf_rfile = file;
858*7c478bd9Sstevel@tonic-gate 			sdf->sdf_flags |= FLG_SDF_VERIFY;
859*7c478bd9Sstevel@tonic-gate 		}
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 		for (_cnt = 0; cnt; _cnt++, cnt--,
862*7c478bd9Sstevel@tonic-gate 		    vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next)) {
863*7c478bd9Sstevel@tonic-gate 			if (!(sdv =
864*7c478bd9Sstevel@tonic-gate 			    libld_calloc(sizeof (Sdv_desc), 1)))
865*7c478bd9Sstevel@tonic-gate 				return (S_ERROR);
866*7c478bd9Sstevel@tonic-gate 			sdv->sdv_name = str + vnap->vna_name;
867*7c478bd9Sstevel@tonic-gate 			sdv->sdv_ref = file;
868*7c478bd9Sstevel@tonic-gate 			if (list_appendc(&sdf->sdf_vers, sdv) == 0)
869*7c478bd9Sstevel@tonic-gate 				return (S_ERROR);
870*7c478bd9Sstevel@tonic-gate 			DBG_CALL(Dbg_ver_need_entry(_cnt, name, sdv->sdv_name));
871*7c478bd9Sstevel@tonic-gate 		}
872*7c478bd9Sstevel@tonic-gate 	}
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate 	return (1);
875*7c478bd9Sstevel@tonic-gate }
876*7c478bd9Sstevel@tonic-gate 
877*7c478bd9Sstevel@tonic-gate /*
878*7c478bd9Sstevel@tonic-gate  * If a symbol is obtained from a versioned relocatable object then the symbols
879*7c478bd9Sstevel@tonic-gate  * version association must be promoted to the version definition as it will be
880*7c478bd9Sstevel@tonic-gate  * represented in the output file.
881*7c478bd9Sstevel@tonic-gate  */
882*7c478bd9Sstevel@tonic-gate void
883*7c478bd9Sstevel@tonic-gate vers_promote(Sym_desc *sdp, Word ndx, Ifl_desc *ifl, Ofl_desc *ofl)
884*7c478bd9Sstevel@tonic-gate {
885*7c478bd9Sstevel@tonic-gate 	Half 	vndx;
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	/*
888*7c478bd9Sstevel@tonic-gate 	 * A version symbol index of 0 implies the symbol is local.  A value of
889*7c478bd9Sstevel@tonic-gate 	 * VER_NDX_GLOBAL implies the symbol is global but has not been
890*7c478bd9Sstevel@tonic-gate 	 * assigned to a specfic version definition.
891*7c478bd9Sstevel@tonic-gate 	 */
892*7c478bd9Sstevel@tonic-gate 	vndx = ifl->ifl_versym[ndx];
893*7c478bd9Sstevel@tonic-gate 	if (vndx == 0) {
894*7c478bd9Sstevel@tonic-gate 		sdp->sd_flags |= FLG_SY_REDUCED;
895*7c478bd9Sstevel@tonic-gate 		sdp->sd_flags1 |= FLG_SY1_LOCL;
896*7c478bd9Sstevel@tonic-gate 		return;
897*7c478bd9Sstevel@tonic-gate 	}
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	if (vndx == VER_NDX_ELIMINATE) {
900*7c478bd9Sstevel@tonic-gate 		sdp->sd_flags |= FLG_SY_REDUCED;
901*7c478bd9Sstevel@tonic-gate 		sdp->sd_flags1 |= (FLG_SY1_LOCL | FLG_SY1_ELIM);
902*7c478bd9Sstevel@tonic-gate 		return;
903*7c478bd9Sstevel@tonic-gate 	}
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	if (vndx == VER_NDX_GLOBAL) {
906*7c478bd9Sstevel@tonic-gate 		if (!(sdp->sd_flags1 & FLG_SY1_LOCL)) {
907*7c478bd9Sstevel@tonic-gate 			sdp->sd_flags1 |= FLG_SY1_GLOB;
908*7c478bd9Sstevel@tonic-gate 			sdp->sd_aux->sa_overndx = VER_NDX_GLOBAL;
909*7c478bd9Sstevel@tonic-gate 		}
910*7c478bd9Sstevel@tonic-gate 		return;
911*7c478bd9Sstevel@tonic-gate 	}
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 	/*
914*7c478bd9Sstevel@tonic-gate 	 * Any other version index requires association to the appropriate
915*7c478bd9Sstevel@tonic-gate 	 * version definition.
916*7c478bd9Sstevel@tonic-gate 	 */
917*7c478bd9Sstevel@tonic-gate 	if ((ifl->ifl_verndx == 0) || (vndx > ifl->ifl_vercnt)) {
918*7c478bd9Sstevel@tonic-gate 		eprintf(ERR_FATAL, MSG_INTL(MSG_VER_INVALNDX), sdp->sd_name,
919*7c478bd9Sstevel@tonic-gate 		    ifl->ifl_name, vndx);
920*7c478bd9Sstevel@tonic-gate 		ofl->ofl_flags |= FLG_OF_FATAL;
921*7c478bd9Sstevel@tonic-gate 		return;
922*7c478bd9Sstevel@tonic-gate 	}
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 	if (!(sdp->sd_flags1 & FLG_SY1_LOCL))
925*7c478bd9Sstevel@tonic-gate 		sdp->sd_flags1 |= FLG_SY1_GLOB;
926*7c478bd9Sstevel@tonic-gate 
927*7c478bd9Sstevel@tonic-gate 	/*
928*7c478bd9Sstevel@tonic-gate 	 * Promote the symbols version index to the appropriate output version
929*7c478bd9Sstevel@tonic-gate 	 * definition.
930*7c478bd9Sstevel@tonic-gate 	 */
931*7c478bd9Sstevel@tonic-gate 	if (!(sdp->sd_flags & FLG_SY_VERSPROM)) {
932*7c478bd9Sstevel@tonic-gate 		Ver_index	*vip;
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 		vip = &ifl->ifl_verndx[vndx];
935*7c478bd9Sstevel@tonic-gate 		sdp->sd_aux->sa_overndx = vip->vi_desc->vd_ref->vd_ndx;
936*7c478bd9Sstevel@tonic-gate 		sdp->sd_flags |= FLG_SY_VERSPROM;
937*7c478bd9Sstevel@tonic-gate 	}
938*7c478bd9Sstevel@tonic-gate }
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate /*
941*7c478bd9Sstevel@tonic-gate  * If any versioning is called for make sure an initial version descriptor is
942*7c478bd9Sstevel@tonic-gate  * assigned to represent the file itself.  Known as the base version.
943*7c478bd9Sstevel@tonic-gate  */
944*7c478bd9Sstevel@tonic-gate Ver_desc *
945*7c478bd9Sstevel@tonic-gate vers_base(Ofl_desc *ofl)
946*7c478bd9Sstevel@tonic-gate {
947*7c478bd9Sstevel@tonic-gate 	Ver_desc	*vdp;
948*7c478bd9Sstevel@tonic-gate 	const char	*name;
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 	/*
951*7c478bd9Sstevel@tonic-gate 	 * Determine the filename to associate to the version descriptor.  This
952*7c478bd9Sstevel@tonic-gate 	 * is either the SONAME (if one has been supplied) or the basename of
953*7c478bd9Sstevel@tonic-gate 	 * the output file.
954*7c478bd9Sstevel@tonic-gate 	 */
955*7c478bd9Sstevel@tonic-gate 	if ((name = ofl->ofl_soname) == 0) {
956*7c478bd9Sstevel@tonic-gate 		const char	*str = ofl->ofl_name;
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 		while (*str != '\0') {
959*7c478bd9Sstevel@tonic-gate 			if (*str++ == '/')
960*7c478bd9Sstevel@tonic-gate 				name = str;
961*7c478bd9Sstevel@tonic-gate 		}
962*7c478bd9Sstevel@tonic-gate 		if (name == 0)
963*7c478bd9Sstevel@tonic-gate 			name = ofl->ofl_name;
964*7c478bd9Sstevel@tonic-gate 	}
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	/*
967*7c478bd9Sstevel@tonic-gate 	 * Generate the version descriptor.
968*7c478bd9Sstevel@tonic-gate 	 */
969*7c478bd9Sstevel@tonic-gate 	/* LINTED */
970*7c478bd9Sstevel@tonic-gate 	if ((vdp = vers_desc(name, (Word)elf_hash(name), &ofl->ofl_verdesc)) ==
971*7c478bd9Sstevel@tonic-gate 	    (Ver_desc *)S_ERROR)
972*7c478bd9Sstevel@tonic-gate 		return ((Ver_desc *)S_ERROR);
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 	/*
975*7c478bd9Sstevel@tonic-gate 	 * Assign the base index to this version and initialize the output file
976*7c478bd9Sstevel@tonic-gate 	 * descriptor with the number of version descriptors presently in use.
977*7c478bd9Sstevel@tonic-gate 	 */
978*7c478bd9Sstevel@tonic-gate 	vdp->vd_ndx = ofl->ofl_vercnt = VER_NDX_GLOBAL;
979*7c478bd9Sstevel@tonic-gate 	vdp->vd_flags |= VER_FLG_BASE;
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 	return (vdp);
982*7c478bd9Sstevel@tonic-gate }
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate /*
985*7c478bd9Sstevel@tonic-gate  * Now that all input shared objects have been processed, verify that all
986*7c478bd9Sstevel@tonic-gate  * version requirements have been met.  Any version control requirements will
987*7c478bd9Sstevel@tonic-gate  * have been specified by the user (and placed on the ofl_oscntl list) and are
988*7c478bd9Sstevel@tonic-gate  * verified at the time the object was processed (see ver_def_process()).
989*7c478bd9Sstevel@tonic-gate  * Here we process all version requirements established from shared objects
990*7c478bd9Sstevel@tonic-gate  * themselves (ie,. NEEDED dependencies).
991*7c478bd9Sstevel@tonic-gate  */
992*7c478bd9Sstevel@tonic-gate int
993*7c478bd9Sstevel@tonic-gate vers_verify(Ofl_desc *ofl)
994*7c478bd9Sstevel@tonic-gate {
995*7c478bd9Sstevel@tonic-gate 	Listnode	*lnp1;
996*7c478bd9Sstevel@tonic-gate 	Sdf_desc	*sdf;
997*7c478bd9Sstevel@tonic-gate 	char		*nv;
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 	/*
1000*7c478bd9Sstevel@tonic-gate 	 * As with the runtime environment, disable all version verification if
1001*7c478bd9Sstevel@tonic-gate 	 * requested.
1002*7c478bd9Sstevel@tonic-gate 	 */
1003*7c478bd9Sstevel@tonic-gate #if	defined(_ELF64)
1004*7c478bd9Sstevel@tonic-gate 	if ((nv = getenv(MSG_ORIG(MSG_LD_NOVERSION_64))) == NULL)
1005*7c478bd9Sstevel@tonic-gate #else
1006*7c478bd9Sstevel@tonic-gate 	if ((nv = getenv(MSG_ORIG(MSG_LD_NOVERSION_32))) == NULL)
1007*7c478bd9Sstevel@tonic-gate #endif
1008*7c478bd9Sstevel@tonic-gate 	    nv = getenv(MSG_ORIG(MSG_LD_NOVERSION));
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	if (nv && (*nv != '\0'))
1011*7c478bd9Sstevel@tonic-gate 		return (1);
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ofl->ofl_soneed, lnp1, sdf)) {
1014*7c478bd9Sstevel@tonic-gate 		Listnode	*lnp2;
1015*7c478bd9Sstevel@tonic-gate 		Sdv_desc	*sdv;
1016*7c478bd9Sstevel@tonic-gate 		Ifl_desc	*ifl = sdf->sdf_file;
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 		if (!(sdf->sdf_flags & FLG_SDF_VERIFY))
1019*7c478bd9Sstevel@tonic-gate 			continue;
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 		/*
1022*7c478bd9Sstevel@tonic-gate 		 * If this file contains no version definitions then ignore
1023*7c478bd9Sstevel@tonic-gate 		 * any versioning verification.  This is the same model as
1024*7c478bd9Sstevel@tonic-gate 		 * carried out by ld.so.1 and is intended to allow backward
1025*7c478bd9Sstevel@tonic-gate 		 * compatibility should a shared object with a version
1026*7c478bd9Sstevel@tonic-gate 		 * requirment be returned to an older system on which a
1027*7c478bd9Sstevel@tonic-gate 		 * non-versioned shared object exists.
1028*7c478bd9Sstevel@tonic-gate 		 */
1029*7c478bd9Sstevel@tonic-gate 		if ((ifl == 0) || (ifl->ifl_verdesc.head == 0))
1030*7c478bd9Sstevel@tonic-gate 			continue;
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 		/*
1033*7c478bd9Sstevel@tonic-gate 		 * If individual versions were specified for this file make
1034*7c478bd9Sstevel@tonic-gate 		 * sure that they actually exist in the appropriate file, and
1035*7c478bd9Sstevel@tonic-gate 		 * that they are available for binding.
1036*7c478bd9Sstevel@tonic-gate 		 */
1037*7c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&sdf->sdf_vers, lnp2, sdv)) {
1038*7c478bd9Sstevel@tonic-gate 			Listnode	*lnp3;
1039*7c478bd9Sstevel@tonic-gate 			Ver_desc	*vdp;
1040*7c478bd9Sstevel@tonic-gate 			int		found = 0;
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 			for (LIST_TRAVERSE(&ifl->ifl_verdesc, lnp3, vdp)) {
1043*7c478bd9Sstevel@tonic-gate 				if (strcmp(sdv->sdv_name, vdp->vd_name) == 0) {
1044*7c478bd9Sstevel@tonic-gate 					found++;
1045*7c478bd9Sstevel@tonic-gate 					break;
1046*7c478bd9Sstevel@tonic-gate 				}
1047*7c478bd9Sstevel@tonic-gate 			}
1048*7c478bd9Sstevel@tonic-gate 			if (found) {
1049*7c478bd9Sstevel@tonic-gate 				Ver_index	*vip;
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate 				vip = &ifl->ifl_verndx[vdp->vd_ndx];
1052*7c478bd9Sstevel@tonic-gate 				if (!(vip->vi_flags & FLG_VER_AVAIL)) {
1053*7c478bd9Sstevel@tonic-gate 					eprintf(ERR_FATAL,
1054*7c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_VER_UNAVAIL),
1055*7c478bd9Sstevel@tonic-gate 					    ifl->ifl_name, sdv->sdv_name,
1056*7c478bd9Sstevel@tonic-gate 					    sdv->sdv_ref);
1057*7c478bd9Sstevel@tonic-gate 					ofl->ofl_flags |= FLG_OF_FATAL;
1058*7c478bd9Sstevel@tonic-gate 				}
1059*7c478bd9Sstevel@tonic-gate 			} else {
1060*7c478bd9Sstevel@tonic-gate 				eprintf(ERR_FATAL, MSG_INTL(MSG_VER_NOEXIST),
1061*7c478bd9Sstevel@tonic-gate 				    ifl->ifl_name, sdv->sdv_name, sdv->sdv_ref);
1062*7c478bd9Sstevel@tonic-gate 				ofl->ofl_flags |= FLG_OF_FATAL;
1063*7c478bd9Sstevel@tonic-gate 			}
1064*7c478bd9Sstevel@tonic-gate 		}
1065*7c478bd9Sstevel@tonic-gate 	}
1066*7c478bd9Sstevel@tonic-gate 	return (1);
1067*7c478bd9Sstevel@tonic-gate }
1068