xref: /illumos-gate/usr/src/cmd/sgs/libld/common/groups.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include	<stdio.h>
30*7c478bd9Sstevel@tonic-gate #include	<string.h>
31*7c478bd9Sstevel@tonic-gate #include	<link.h>
32*7c478bd9Sstevel@tonic-gate #include	"debug.h"
33*7c478bd9Sstevel@tonic-gate #include	"msg.h"
34*7c478bd9Sstevel@tonic-gate #include	"_libld.h"
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate /*
38*7c478bd9Sstevel@tonic-gate  * Given a group signature symbol - scan through the global list
39*7c478bd9Sstevel@tonic-gate  * of GROUP sections to determine if we have a conflict/discard.
40*7c478bd9Sstevel@tonic-gate  * If this is the first time we see a group signature - add it to the
41*7c478bd9Sstevel@tonic-gate  * global list.
42*7c478bd9Sstevel@tonic-gate  *
43*7c478bd9Sstevel@tonic-gate  * Returns:
44*7c478bd9Sstevel@tonic-gate  *		0	-	Group kept and added to global list.
45*7c478bd9Sstevel@tonic-gate  *		1	-	Group should be discarded.
46*7c478bd9Sstevel@tonic-gate  */
47*7c478bd9Sstevel@tonic-gate uintptr_t
48*7c478bd9Sstevel@tonic-gate scan_global_groups(Group_desc * gdesc, Ofl_desc * ofl)
49*7c478bd9Sstevel@tonic-gate {
50*7c478bd9Sstevel@tonic-gate 	Group_desc *	_gdesc;
51*7c478bd9Sstevel@tonic-gate 	Listnode *	lnp;
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate 	/*
54*7c478bd9Sstevel@tonic-gate 	 * Scan through global list - if we find a group of the
55*7c478bd9Sstevel@tonic-gate 	 * same name - we return 0 saying this new group should
56*7c478bd9Sstevel@tonic-gate 	 * be discarded (since only COMDAT's get here currently).
57*7c478bd9Sstevel@tonic-gate 	 */
58*7c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ofl->ofl_groups, lnp, _gdesc))
59*7c478bd9Sstevel@tonic-gate 		if (strcmp(_gdesc->gd_symname, gdesc->gd_symname) == 0) {
60*7c478bd9Sstevel@tonic-gate 			gdesc->gd_flags |= GRP_FLG_DISCARD;
61*7c478bd9Sstevel@tonic-gate 			return (1);
62*7c478bd9Sstevel@tonic-gate 		}
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	if (list_appendc(&ofl->ofl_groups, gdesc) == 0)
65*7c478bd9Sstevel@tonic-gate 		return (S_ERROR);
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 	return (0);
68*7c478bd9Sstevel@tonic-gate }
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate Group_desc *
72*7c478bd9Sstevel@tonic-gate get_group_desc(Ofl_desc *ofl, Is_desc *isp)
73*7c478bd9Sstevel@tonic-gate {
74*7c478bd9Sstevel@tonic-gate 	Ifl_desc	*ifl = isp->is_file;
75*7c478bd9Sstevel@tonic-gate 	Elf		*elf = ifl->ifl_elf;
76*7c478bd9Sstevel@tonic-gate 	uint_t		scnndx = isp->is_scnndx;
77*7c478bd9Sstevel@tonic-gate 	Group_desc	*gdesc;
78*7c478bd9Sstevel@tonic-gate 	Listnode	*lnp;
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 	/*
82*7c478bd9Sstevel@tonic-gate 	 * If this is the first section of with the SHF_GROUP flag
83*7c478bd9Sstevel@tonic-gate 	 * set - then we havn't yet scanned for - and found our
84*7c478bd9Sstevel@tonic-gate 	 * group sections.  If thats so - do it now.
85*7c478bd9Sstevel@tonic-gate 	 */
86*7c478bd9Sstevel@tonic-gate 	if (ifl->ifl_groups.head == 0) {
87*7c478bd9Sstevel@tonic-gate 		Elf_Scn		*scn = 0;
88*7c478bd9Sstevel@tonic-gate 		while (scn = elf_nextscn(elf, scn)) {
89*7c478bd9Sstevel@tonic-gate 			Shdr		*shdr;
90*7c478bd9Sstevel@tonic-gate 			Shdr		*_shdr;
91*7c478bd9Sstevel@tonic-gate 			Sym		*sym;
92*7c478bd9Sstevel@tonic-gate 			const char	*symname;
93*7c478bd9Sstevel@tonic-gate 			Elf_Scn		*_scn;
94*7c478bd9Sstevel@tonic-gate 			Elf_Data	*data;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 			shdr = elf_getshdr(scn);
97*7c478bd9Sstevel@tonic-gate 			if (shdr->sh_type != SHT_GROUP)
98*7c478bd9Sstevel@tonic-gate 				continue;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 			/*
101*7c478bd9Sstevel@tonic-gate 			 * Confirm that the sh_link points to a
102*7c478bd9Sstevel@tonic-gate 			 * valid section.
103*7c478bd9Sstevel@tonic-gate 			 */
104*7c478bd9Sstevel@tonic-gate 			if ((shdr->sh_link == SHN_UNDEF) ||
105*7c478bd9Sstevel@tonic-gate 			    (shdr->sh_link >= ifl->ifl_shnum)) {
106*7c478bd9Sstevel@tonic-gate 				eprintf(ERR_FATAL, MSG_INTL(MSG_FIL_INVSHLINK),
107*7c478bd9Sstevel@tonic-gate 					ifl->ifl_name, elf_strptr(elf,
108*7c478bd9Sstevel@tonic-gate 					ifl->ifl_shstrndx,
109*7c478bd9Sstevel@tonic-gate 					shdr->sh_name),
110*7c478bd9Sstevel@tonic-gate 					EC_XWORD(shdr->sh_link));
111*7c478bd9Sstevel@tonic-gate 				ofl->ofl_flags |= FLG_OF_FATAL;
112*7c478bd9Sstevel@tonic-gate 				continue;
113*7c478bd9Sstevel@tonic-gate 			}
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 			if (shdr->sh_entsize == 0) {
116*7c478bd9Sstevel@tonic-gate 				eprintf(ERR_FATAL,
117*7c478bd9Sstevel@tonic-gate 					MSG_INTL(MSG_FIL_INVSHENTSIZE),
118*7c478bd9Sstevel@tonic-gate 					ifl->ifl_name, elf_strptr(elf,
119*7c478bd9Sstevel@tonic-gate 					ifl->ifl_shstrndx,
120*7c478bd9Sstevel@tonic-gate 					shdr->sh_name),
121*7c478bd9Sstevel@tonic-gate 					EC_XWORD(shdr->sh_entsize));
122*7c478bd9Sstevel@tonic-gate 				ofl->ofl_flags |= FLG_OF_FATAL;
123*7c478bd9Sstevel@tonic-gate 				continue;
124*7c478bd9Sstevel@tonic-gate 			}
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 			/*
127*7c478bd9Sstevel@tonic-gate 			 * Get associated symbol table
128*7c478bd9Sstevel@tonic-gate 			 */
129*7c478bd9Sstevel@tonic-gate 			_scn = elf_getscn(elf, shdr->sh_link);
130*7c478bd9Sstevel@tonic-gate 			_shdr = elf_getshdr(_scn);
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 			/*
133*7c478bd9Sstevel@tonic-gate 			 * Sanity check the sh_link field (which points to
134*7c478bd9Sstevel@tonic-gate 			 * a symbol table entry) against the size of the
135*7c478bd9Sstevel@tonic-gate 			 * symbol table.
136*7c478bd9Sstevel@tonic-gate 			 */
137*7c478bd9Sstevel@tonic-gate 			if ((shdr->sh_info == SHN_UNDEF) ||
138*7c478bd9Sstevel@tonic-gate 			    (shdr->sh_info >= (Word)(_shdr->sh_size /
139*7c478bd9Sstevel@tonic-gate 			    _shdr->sh_entsize))) {
140*7c478bd9Sstevel@tonic-gate 				eprintf(ERR_FATAL, MSG_INTL(MSG_FIL_INVSHINFO),
141*7c478bd9Sstevel@tonic-gate 					ifl->ifl_name, elf_strptr(elf,
142*7c478bd9Sstevel@tonic-gate 					ifl->ifl_shstrndx,
143*7c478bd9Sstevel@tonic-gate 					shdr->sh_name),
144*7c478bd9Sstevel@tonic-gate 					EC_XWORD(shdr->sh_info));
145*7c478bd9Sstevel@tonic-gate 				ofl->ofl_flags |= FLG_OF_FATAL;
146*7c478bd9Sstevel@tonic-gate 				continue;
147*7c478bd9Sstevel@tonic-gate 			}
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 			data = elf_getdata(_scn, 0);
150*7c478bd9Sstevel@tonic-gate 			sym = data->d_buf;
151*7c478bd9Sstevel@tonic-gate 			sym += shdr->sh_info;
152*7c478bd9Sstevel@tonic-gate 			symname = elf_strptr(elf, _shdr->sh_link, sym->st_name);
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 			if ((gdesc = libld_calloc(sizeof (Group_desc), 1)) == 0)
155*7c478bd9Sstevel@tonic-gate 				return ((Group_desc *)S_ERROR);
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 			gdesc->gd_gsectname = elf_strptr(elf,
158*7c478bd9Sstevel@tonic-gate 				ifl->ifl_shstrndx, shdr->sh_name);
159*7c478bd9Sstevel@tonic-gate 			gdesc->gd_symname = symname;
160*7c478bd9Sstevel@tonic-gate 			gdesc->gd_sym = sym;
161*7c478bd9Sstevel@tonic-gate 			gdesc->gd_scn = scn;
162*7c478bd9Sstevel@tonic-gate 			data = elf_getdata(scn, 0);
163*7c478bd9Sstevel@tonic-gate 			gdesc->gd_groupdata = data->d_buf;
164*7c478bd9Sstevel@tonic-gate 			gdesc->gd_gdcnt = data->d_size / sizeof (Word);
165*7c478bd9Sstevel@tonic-gate 			/*
166*7c478bd9Sstevel@tonic-gate 			 * If this group is a COMDAT group - then we
167*7c478bd9Sstevel@tonic-gate 			 * need to find the 'signature' symbol to determine
168*7c478bd9Sstevel@tonic-gate 			 * if this is group is to be kept or discarded.
169*7c478bd9Sstevel@tonic-gate 			 */
170*7c478bd9Sstevel@tonic-gate 			if (gdesc->gd_groupdata[0] & GRP_COMDAT) {
171*7c478bd9Sstevel@tonic-gate 				if ((ELF_ST_BIND(sym->st_info) != STB_LOCAL) &&
172*7c478bd9Sstevel@tonic-gate 				    (sym->st_shndx != SHN_UNDEF)) {
173*7c478bd9Sstevel@tonic-gate 					if (scan_global_groups(gdesc, ofl)
174*7c478bd9Sstevel@tonic-gate 					    == S_ERROR)
175*7c478bd9Sstevel@tonic-gate 						return ((Group_desc *)S_ERROR);
176*7c478bd9Sstevel@tonic-gate 				}
177*7c478bd9Sstevel@tonic-gate 			}
178*7c478bd9Sstevel@tonic-gate 			if (list_appendc(&ifl->ifl_groups, gdesc) == 0)
179*7c478bd9Sstevel@tonic-gate 				return ((Group_desc *)S_ERROR);
180*7c478bd9Sstevel@tonic-gate 		}
181*7c478bd9Sstevel@tonic-gate 	}
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	/*
184*7c478bd9Sstevel@tonic-gate 	 * Now we scan through the GROUP sections associated with
185*7c478bd9Sstevel@tonic-gate 	 * this file - to find the matching group section.
186*7c478bd9Sstevel@tonic-gate 	 */
187*7c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ifl->ifl_groups, lnp, gdesc)) {
188*7c478bd9Sstevel@tonic-gate 		size_t	i;
189*7c478bd9Sstevel@tonic-gate 		Word *	gdata;
190*7c478bd9Sstevel@tonic-gate 		if (isp->is_shdr->sh_type == SHT_GROUP) {
191*7c478bd9Sstevel@tonic-gate 			if ((size_t)isp->is_scnndx ==
192*7c478bd9Sstevel@tonic-gate 			    elf_ndxscn(gdesc->gd_scn)) {
193*7c478bd9Sstevel@tonic-gate 				isp->is_group = gdesc;
194*7c478bd9Sstevel@tonic-gate 				return (gdesc);
195*7c478bd9Sstevel@tonic-gate 			}
196*7c478bd9Sstevel@tonic-gate 			continue;
197*7c478bd9Sstevel@tonic-gate 		}
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 		gdata = gdesc->gd_groupdata;
200*7c478bd9Sstevel@tonic-gate 		for (i = 1; i < gdesc->gd_gdcnt; i++) {
201*7c478bd9Sstevel@tonic-gate 			if (gdata[i] == scnndx) {
202*7c478bd9Sstevel@tonic-gate 				isp->is_group = gdesc;
203*7c478bd9Sstevel@tonic-gate 				return (gdesc);
204*7c478bd9Sstevel@tonic-gate 			}
205*7c478bd9Sstevel@tonic-gate 		}
206*7c478bd9Sstevel@tonic-gate 	}
207*7c478bd9Sstevel@tonic-gate 	eprintf(ERR_FATAL, MSG_INTL(MSG_ELF_NOGROUPSECT), ifl->ifl_name,
208*7c478bd9Sstevel@tonic-gate 		isp->is_name);
209*7c478bd9Sstevel@tonic-gate 	ofl->ofl_flags |= FLG_OF_FATAL;
210*7c478bd9Sstevel@tonic-gate 	return ((Group_desc *)0);
211*7c478bd9Sstevel@tonic-gate }
212