xref: /illumos-gate/usr/src/cmd/sgs/libld/common/order.c (revision b76c1459)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Processing of SHF_ORDERED sections.
29  */
30 #include	<stdio.h>
31 #include	<fcntl.h>
32 #include	<link.h>
33 #include	<debug.h>
34 #include	"msg.h"
35 #include	"_libld.h"
36 
37 /*
38  * Part 1, Input processing.
39  */
40 /*
41  * Get the head section number
42  */
43 inline static Word
44 is_keylink_ok(Ifl_desc *ifl, Word keylink, Word limit)
45 {
46 	if ((keylink == SHN_BEFORE) || (keylink == SHN_AFTER))
47 		return (0);
48 
49 	/*
50 	 * Validate the key range.
51 	 */
52 	if ((keylink == 0) || (keylink >= limit))
53 		return (DBG_ORDER_LINK_OUTRANGE);
54 
55 	/*
56 	 * The section pointed to by keylink should not be an ordered section.
57 	 */
58 	if (ifl->ifl_isdesc[keylink]->is_shdr->sh_flags & ALL_SHF_ORDER)
59 		return (DBG_ORDER_INFO_ORDER);
60 
61 	return (0);
62 }
63 
64 /*
65  * Get the head section number.
66  */
67 static Word
68 get_shfordered_dest(Ofl_desc *ofl, Ifl_desc *ifl, Word ndx, Word limit)
69 {
70 	Word	t1_link = ndx, t2_link, ret_link;
71 	Is_desc *isp, *isp1, *isp2;
72 	int	error = 0;
73 
74 	/*
75 	 * Check the sh_info of myself.
76 	 */
77 	isp = ifl->ifl_isdesc[ndx];
78 
79 	isp1 = isp;
80 	ret_link = t2_link = isp1->is_shdr->sh_link;
81 	t1_link = ndx;
82 	do {
83 		/*
84 		 * Check the validitiy of the link
85 		 */
86 		if (t2_link == 0 || t2_link >= limit) {
87 			error = DBG_ORDER_LINK_OUTRANGE;
88 			break;
89 		}
90 		isp2 = ifl->ifl_isdesc[t2_link];
91 
92 		/*
93 		 * Pointing to a bad ordered section ?
94 		 */
95 		if ((isp2->is_flags & FLG_IS_ORDERED) == 0) {
96 			error = DBG_ORDER_LINK_ERROR;
97 			break;
98 		}
99 
100 		/*
101 		 * Check sh_flag
102 		 */
103 		if (isp1->is_shdr->sh_flags != isp2->is_shdr->sh_flags) {
104 			error = DBG_ORDER_FLAGS;
105 			break;
106 		}
107 
108 		/*
109 		 * Check the validity of sh_info field.
110 		 */
111 		if ((error = is_keylink_ok(ifl,
112 		    isp->is_shdr->sh_info, limit)) != 0) {
113 			break;
114 		}
115 
116 		/*
117 		 * Can I break ?
118 		 */
119 		if (t1_link == t2_link)
120 			break;
121 
122 		/*
123 		 * Get the next link
124 		 */
125 		t1_link = t2_link;
126 		isp1 = ifl->ifl_isdesc[t1_link];
127 		ret_link = t2_link = isp1->is_shdr->sh_link;
128 
129 		/*
130 		 * Cyclic ?
131 		 */
132 		if (t2_link == ndx) {
133 			error = DBG_ORDER_CYCLIC;
134 			break;
135 		}
136 	/* CONSTANTCONDITION */
137 	} while (1);
138 
139 	if (error != 0) {
140 		ret_link = 0;
141 		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
142 	}
143 	return (ret_link);
144 }
145 
146 /*
147  * Called from process_elf().
148  * This routine does the input processing of the ordered sections.
149  */
150 uintptr_t
151 ld_process_ordered(Ifl_desc *ifl, Ofl_desc *ofl, Word ndx)
152 {
153 	Is_desc		*isp2, *isp = ifl->ifl_isdesc[ndx];
154 	Xword		shflags = isp->is_shdr->sh_flags;
155 	Word		keylink, dest_ndx, limit = ifl->ifl_shnum;
156 	Os_desc		*osp2, *osp;
157 	Sort_desc	*st;
158 	Aliste		idx;
159 	int		error = 0;
160 
161 	/*
162 	 * This section might have been checked and marked in error already.
163 	 */
164 	if ((isp->is_flags & FLG_IS_ORDERED) == 0)
165 		return (0);
166 
167 	if (shflags & SHF_ORDERED)
168 		keylink = isp->is_shdr->sh_info;
169 	else if (shflags & SHF_LINK_ORDER)
170 		keylink = isp->is_shdr->sh_link;
171 	else
172 		keylink = 0;
173 
174 	if ((error = is_keylink_ok(ifl, keylink, limit)) != 0) {
175 		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
176 		isp->is_flags &= ~FLG_IS_ORDERED;
177 		if (isp->is_osdesc == NULL) {
178 			return ((uintptr_t)ld_place_section(ofl, isp,
179 			    isp->is_keyident, 0));
180 		}
181 		return ((uintptr_t)isp->is_osdesc);
182 	}
183 
184 	/*
185 	 * If SHF_ORDERED is in effect, search for our destination section based
186 	 * off of sh_link, otherwise follow the default rules for the
187 	 * destination section.
188 	 */
189 	if (shflags & SHF_ORDERED) {
190 		if ((dest_ndx = get_shfordered_dest(ofl, ifl,
191 		    ndx, limit)) == 0) {
192 			isp->is_flags &= ~FLG_IS_ORDERED;
193 			if (isp->is_osdesc == NULL) {
194 				return ((uintptr_t)ld_place_section(ofl, isp,
195 				    isp->is_keyident, 0));
196 			}
197 			return ((uintptr_t)isp->is_osdesc);
198 		}
199 	} else {
200 		/*
201 		 * SHF_LINK_ORDER coalesces into default sections, set dest_ndx
202 		 * to NULL to trigger this.
203 		 */
204 		dest_ndx = 0;
205 	}
206 
207 	/*
208 	 * Place the section into its output section. It's possible that this
209 	 * section is discarded (possibly because it's defined COMDAT), in
210 	 * which case we're done.
211 	 */
212 	if ((osp = isp->is_osdesc) == NULL) {
213 		if ((osp = ld_place_section(ofl, isp, isp->is_keyident,
214 		    dest_ndx)) == (Os_desc *)S_ERROR)
215 			return ((uintptr_t)S_ERROR);
216 		if (!osp)
217 			return (0);
218 	}
219 
220 	/*
221 	 * If the output section is not yet on the ordered list, place it on
222 	 * the list.
223 	 */
224 	osp2 = NULL;
225 	for (APLIST_TRAVERSE(ofl->ofl_ordered, idx, osp2)) {
226 		if (osp2 == osp)
227 			break;
228 	}
229 
230 	if ((osp != osp2) && (aplist_append(&(ofl->ofl_ordered),
231 	    osp, AL_CNT_OFL_ORDERED) == NULL))
232 		return ((uintptr_t)S_ERROR);
233 
234 	/*
235 	 * Output section has been found - set up it's sorting information.
236 	 */
237 	if ((osp->os_sort == NULL) &&
238 	    ((osp->os_sort = libld_calloc(1, sizeof (Sort_desc))) == NULL))
239 		return (S_ERROR);
240 
241 	st = osp->os_sort;
242 
243 	if (keylink == SHN_BEFORE) {
244 		st->st_beforecnt++;
245 	} else if (keylink == SHN_AFTER) {
246 		st->st_aftercnt++;
247 	} else {
248 		st->st_ordercnt++;
249 		isp2 = ifl->ifl_isdesc[keylink];
250 		if (isp2->is_flags & FLG_IS_DISCARD) {
251 			eprintf(ofl->ofl_lml, ERR_FATAL,
252 			    MSG_INTL(MSG_FIL_BADORDREF), ifl->ifl_name,
253 			    isp->is_name, isp->is_scnndx, isp2->is_name,
254 			    isp2->is_scnndx);
255 			return (S_ERROR);
256 		}
257 
258 		/*
259 		 * Indicate that this ordered input section will require a sort
260 		 * key created.  Propagate the key requirement through to the
261 		 * associated output section, segment and file, to trigger the
262 		 * sort key creation.  See ld_sec_validate();
263 		 */
264 		isp2->is_flags |= FLG_IS_KEY;
265 
266 		osp2 = isp2->is_osdesc;
267 		osp2->os_flags |= FLG_OS_KEY;
268 		osp2->os_sgdesc->sg_flags |= FLG_SG_KEY;
269 
270 		ofl->ofl_flags |= FLG_OF_KEY;
271 	}
272 
273 	return ((uintptr_t)osp);
274 }
275 
276 /*
277  * Part 2, Sorting processing
278  */
279 
280 /*
281  * Traverse all segments looking for section ordering information that hasn't
282  * been used.  If found give a warning message to the user.  Also, check if
283  * there are any SHF_ORDERED key sections, and if so set up sort key values.
284  */
285 void
286 ld_sec_validate(Ofl_desc *ofl)
287 {
288 	Aliste		idx1;
289 	Sg_desc		*sgp;
290 	Word 		key = 1;
291 
292 	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
293 		Sec_order	*scop;
294 		Os_desc		*osp;
295 		Aliste		idx2;
296 
297 		for (APLIST_TRAVERSE(sgp->sg_secorder, idx2, scop)) {
298 			if ((scop->sco_flags & FLG_SGO_USED) == 0) {
299 				eprintf(ofl->ofl_lml, ERR_WARNING,
300 				    MSG_INTL(MSG_MAP_SECORDER),
301 				    sgp->sg_name, scop->sco_secname);
302 			}
303 		}
304 		if ((sgp->sg_flags & FLG_SG_KEY) == 0)
305 			continue;
306 
307 		for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
308 			Aliste	idx3;
309 			Is_desc	*isp;
310 
311 			if ((osp->os_flags & FLG_OS_KEY) == 0)
312 				continue;
313 
314 			for (APLIST_TRAVERSE(osp->os_isdescs, idx3, isp)) {
315 				if (isp->is_flags & FLG_IS_KEY)
316 					isp->is_keyident = key++;
317 			}
318 		}
319 	}
320 }
321 
322 static int
323 setup_sortbuf(Os_desc *osp)
324 {
325 	Sort_desc	*st = osp->os_sort;
326 	Word		num_after = 0, num_before = 0, num_order = 0;
327 	Aliste		idx;
328 	Is_desc		*isp;
329 
330 	if ((st == NULL) ||
331 	    ((st->st_ordercnt + st->st_beforecnt + st->st_aftercnt) == 0))
332 		return (0);
333 
334 	/*
335 	 * Get memory
336 	 */
337 	if (st->st_beforecnt && ((st->st_before = libld_calloc(st->st_beforecnt,
338 	    sizeof (Is_desc *))) == NULL))
339 		return (0);
340 
341 	if (st->st_ordercnt && ((st->st_order = libld_calloc(st->st_ordercnt,
342 	    sizeof (Is_desc *))) == NULL))
343 		return (0);
344 
345 	if (st->st_aftercnt && ((st->st_after = libld_calloc(st->st_aftercnt,
346 	    sizeof (Is_desc *))) == NULL))
347 		return (0);
348 
349 	/*
350 	 * Set info.
351 	 */
352 	for (APLIST_TRAVERSE(osp->os_isdescs, idx, isp)) {
353 		Word	keylink = 0;
354 
355 		if ((isp->is_flags & FLG_IS_ORDERED) == 0)
356 			continue;
357 
358 		if (isp->is_shdr->sh_flags & SHF_ORDERED)
359 			keylink = isp->is_shdr->sh_info;
360 		else if (isp->is_shdr->sh_flags & SHF_LINK_ORDER)
361 			keylink = isp->is_shdr->sh_link;
362 
363 		if (keylink == SHN_BEFORE)
364 			st->st_before[num_before++] = isp;
365 		else if (keylink == SHN_AFTER)
366 			st->st_after[num_after++] = isp;
367 		else
368 			st->st_order[num_order++] = isp;
369 	}
370 	return (1);
371 }
372 
373 static int
374 comp(const void *ss1, const void *ss2)
375 {
376 	Is_desc		*s1 = *((Is_desc **)ss1);
377 	Is_desc		*s2 = *((Is_desc **)ss2);
378 	Is_desc		*i1, *i2;
379 	Word		ndx1, ndx2;
380 
381 	if (s1->is_shdr->sh_flags & SHF_ORDERED)
382 		ndx1 = s1->is_shdr->sh_info;
383 	else
384 		ndx1 = s1->is_shdr->sh_link;
385 
386 	if (s2->is_shdr->sh_flags & SHF_ORDERED)
387 		ndx2 = s2->is_shdr->sh_info;
388 	else
389 		ndx2 = s2->is_shdr->sh_link;
390 
391 	i1 = s1->is_file->ifl_isdesc[ndx1];
392 	i2 = s2->is_file->ifl_isdesc[ndx2];
393 
394 	if (i1->is_keyident > i2->is_keyident)
395 		return (1);
396 	if (i1->is_keyident < i2->is_keyident)
397 		return (-1);
398 	return (0);
399 }
400 
401 uintptr_t
402 ld_sort_ordered(Ofl_desc *ofl)
403 {
404 	Aliste	idx1;
405 	Os_desc *osp;
406 
407 	DBG_CALL(Dbg_sec_order_list(ofl, 0));
408 
409 	/*
410 	 * Sort Sections
411 	 */
412 	for (APLIST_TRAVERSE(ofl->ofl_ordered, idx1, osp)) {
413 		int		i;
414 		APlist		*islist = NULL;
415 		Aliste		idx2;
416 		Is_desc		*isp;
417 		Sort_desc	*st = osp->os_sort;
418 
419 		if (setup_sortbuf(osp) == 0)
420 			return (S_ERROR);
421 
422 		islist = osp->os_isdescs;
423 		osp->os_isdescs = NULL;
424 
425 		/*
426 		 * Sorting.
427 		 * First Sort the ordered sections.
428 		 */
429 		if (st->st_ordercnt != 0)
430 			qsort((char *)st->st_order, st->st_ordercnt,
431 			    sizeof (Is_desc *), comp);
432 
433 		/*
434 		 * Place SHN_BEFORE at head of list
435 		 */
436 		for (i = 0; i < st->st_beforecnt; i++) {
437 			if (ld_append_isp(ofl, osp, st->st_before[i], 0) == 0)
438 				return (S_ERROR);
439 		}
440 
441 		/*
442 		 * Next come 'linked' ordered sections
443 		 */
444 		for (i = 0; i < st->st_ordercnt; i++) {
445 			if (ld_append_isp(ofl, osp, st->st_order[i], 0) == 0)
446 				return (S_ERROR);
447 		}
448 
449 		/*
450 		 * Now we list any sections which have no sorting
451 		 * specifications - in the order they were input.
452 		 *
453 		 * We use aplist_append() here instead of ld_append_isp(),
454 		 * because these items have already been inserted once, and
455 		 * we don't want any duplicate entries in osp->os_mstridescs.
456 		 */
457 		for (APLIST_TRAVERSE(islist, idx2, isp)) {
458 			if (isp->is_flags & FLG_IS_ORDERED)
459 				continue;
460 			if (aplist_append(&(osp->os_isdescs),
461 			    isp, AL_CNT_OS_ISDESCS) == NULL)
462 				return (S_ERROR);
463 		}
464 
465 		/*
466 		 * And the end of the list are the SHN_AFTER sections.
467 		 */
468 		for (i = 0; i < st->st_aftercnt; i++) {
469 			if (ld_append_isp(ofl, osp, st->st_after[i], 0) == 0)
470 				return (S_ERROR);
471 		}
472 
473 		if (islist)
474 			free(islist);
475 	}
476 	DBG_CALL(Dbg_sec_order_list(ofl, 1));
477 	return (0);
478 }
479