xref: /illumos-gate/usr/src/cmd/sgs/libld/common/order.c (revision bea83d026ee1bd1b2a2419e1d0232f107a5d7d9b)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Processing of SHF_ORDERED sections.
31  */
32 #include	<stdio.h>
33 #include	<fcntl.h>
34 #include	<link.h>
35 #include	<debug.h>
36 #include	"msg.h"
37 #include	"_libld.h"
38 
39 /*
40  * Part 1, Input processing.
41  */
42 /*
43  * Get the head section number
44  */
45 static Word
46 is_keylink_ok(Ifl_desc *ifl, Word keylink, Word limit)
47 {
48 	if ((keylink != SHN_BEFORE) && (keylink != SHN_AFTER)) {
49 		/*
50 		 * Range Check
51 		 */
52 		if ((keylink == 0) || (keylink >= limit)) {
53 			return (DBG_ORDER_LINK_OUTRANGE);
54 		}
55 
56 		/*
57 		 * The section pointed by keylink should not be an
58 		 * ordered section.
59 		 */
60 		if (ifl->ifl_isdesc[keylink]->is_shdr->sh_flags &
61 		    ALL_SHF_ORDER) {
62 			return (DBG_ORDER_INFO_ORDER);
63 		}
64 	}
65 	return (0);
66 }
67 
68 static Word
69 get_shfordered_dest(Ofl_desc *ofl, Ifl_desc *ifl, Word ndx, Word limit)
70 {
71 	Word t1_link = ndx, t2_link, ret_link;
72 	Is_desc *isp, *isp1, *isp2;
73 	int error = 0;
74 
75 	/*
76 	 * Check the sh_info of myself.
77 	 */
78 	isp = ifl->ifl_isdesc[ndx];
79 
80 	isp1 = isp;
81 	ret_link = t2_link = isp1->is_shdr->sh_link;
82 	t1_link = ndx;
83 	do {
84 		/*
85 		 * Check the validitiy of the link
86 		 */
87 		if (t2_link == 0 || t2_link >= limit) {
88 			error = DBG_ORDER_LINK_OUTRANGE;
89 			break;
90 		}
91 		isp2 = ifl->ifl_isdesc[t2_link];
92 
93 		/*
94 		 * Pointing to a bad ordered section ?
95 		 */
96 		if ((isp2->is_flags & FLG_IS_ORDERED) == 0) {
97 			error = DBG_ORDER_LINK_ERROR;
98 			break;
99 		}
100 
101 		/*
102 		 * Check sh_flag
103 		 */
104 		if (isp1->is_shdr->sh_flags != isp2->is_shdr->sh_flags) {
105 			error = DBG_ORDER_FLAGS;
106 			break;
107 		}
108 
109 		/*
110 		 * Check the validity of sh_info field.
111 		 */
112 		if ((error = is_keylink_ok(ifl,
113 		    isp->is_shdr->sh_info, limit)) != 0) {
114 			break;
115 		}
116 
117 		/*
118 		 * Can I break ?
119 		 */
120 		if (t1_link == t2_link)
121 			break;
122 
123 		/*
124 		 * Get the next link
125 		 */
126 		t1_link = t2_link;
127 		isp1 = ifl->ifl_isdesc[t1_link];
128 		ret_link = t2_link = isp1->is_shdr->sh_link;
129 
130 		/*
131 		 * Cyclic ?
132 		 */
133 		if (t2_link == ndx) {
134 			error = DBG_ORDER_CYCLIC;
135 			break;
136 		}
137 	/* CONSTANTCONDITION */
138 	} while (1);
139 
140 	if (error != 0) {
141 		ret_link = 0;
142 		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
143 	}
144 	return (ret_link);
145 }
146 
147 /*
148  * Called from process_elf().
149  * This routine does the input processing of the ordered sections.
150  */
151 uintptr_t
152 ld_process_ordered(Ifl_desc *ifl, Ofl_desc *ofl, Word ndx, Word limit)
153 {
154 	Is_desc *	isp2, * isp = ifl->ifl_isdesc[ndx];
155 	Xword		shflags = isp->is_shdr->sh_flags;
156 	uint_t		keylink;
157 	Os_desc *	osp2, * osp;
158 	Word		dest_ndx;
159 	Sort_desc *	st;
160 	Listnode *	lnp;
161 	int		error = 0;
162 
163 	/*
164 	 * I might have been checked and marked error already.
165 	 */
166 	if ((isp->is_flags & FLG_IS_ORDERED) == 0)
167 		return (0);
168 
169 	if (shflags & SHF_ORDERED)
170 		keylink = isp->is_shdr->sh_info;
171 	else if (shflags & SHF_LINK_ORDER)
172 		keylink = isp->is_shdr->sh_link;
173 	else
174 		keylink = 0;
175 
176 	if ((error = is_keylink_ok(ifl, keylink, limit)) != 0) {
177 		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
178 		isp->is_flags &= ~FLG_IS_ORDERED;
179 		if (isp->is_osdesc == NULL)
180 			return ((uintptr_t)ld_place_section(ofl, isp,
181 			    isp->is_key, 0));
182 		return ((uintptr_t)isp->is_osdesc);
183 	}
184 
185 	/*
186 	 * If SHF_ORDERED is in effect, search for our destination section based
187 	 * off of sh_link, otherwise follow the default rules for the
188 	 * destination section.
189 	 */
190 	if (shflags & SHF_ORDERED) {
191 		if ((dest_ndx = get_shfordered_dest(ofl, ifl,
192 		    ndx, limit)) == 0) {
193 			isp->is_flags &= ~FLG_IS_ORDERED;
194 			if (isp->is_osdesc == NULL)
195 				return ((uintptr_t)ld_place_section(ofl, isp,
196 				    isp->is_key, 0));
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 it's output section.
209 	 */
210 	if ((osp = isp->is_osdesc) == NULL) {
211 		if ((osp = ld_place_section(ofl, isp, isp->is_ident,
212 		    dest_ndx)) == (Os_desc *)S_ERROR)
213 			return ((uintptr_t)S_ERROR);
214 		if (!osp)
215 			return (0);
216 	}
217 
218 	/*
219 	 * If the output section is not yet on the ordered
220 	 * list - place it on the list.
221 	 */
222 	osp2 = NULL;
223 	for (LIST_TRAVERSE(&ofl->ofl_ordered, lnp, osp2)) {
224 		if (osp2 == osp)
225 			break;
226 	}
227 
228 	if (osp != osp2) {
229 		if (list_appendc(&(ofl->ofl_ordered), osp) == 0)
230 			return ((uintptr_t)S_ERROR);
231 	}
232 
233 	/*
234 	 * Output section has been found - set up it's
235 	 * sorting information.
236 	 */
237 	if (osp->os_sort == 0) {
238 		if ((osp->os_sort = libld_calloc(1, sizeof (Sort_desc))) == 0)
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 		osp2 = isp2->is_osdesc;
258 		osp2->os_flags |= FLG_OS_ORDER_KEY;
259 		osp2->os_sgdesc->sg_flags |= FLG_SG_KEY;
260 		isp2->is_flags |= FLG_IS_KEY;
261 	}
262 
263 	return ((uintptr_t)osp);
264 }
265 
266 /*
267  * Part 2, Sorting processing
268  */
269 
270 /*
271  * Traverse all segments looking for section ordering information that hasn't
272  * been used.  If found give a warning message to the user.  Also, check if
273  * there are any SHF_ORDERED key sections, and if so set up sort key values.
274  */
275 void
276 ld_sec_validate(Ofl_desc *ofl)
277 {
278 	Listnode	*lnp1;
279 	Sg_desc		*sgp;
280 	int 		key = 1;
281 
282 	for (LIST_TRAVERSE(&ofl->ofl_segs, lnp1, sgp)) {
283 		Sec_order	*scop;
284 		Os_desc		*osp;
285 		Aliste		idx;
286 
287 		for (APLIST_TRAVERSE(sgp->sg_secorder, idx, scop)) {
288 			if ((scop->sco_flags & FLG_SGO_USED) == 0) {
289 				eprintf(ofl->ofl_lml, ERR_WARNING,
290 				    MSG_INTL(MSG_MAP_SECORDER),
291 				    sgp->sg_name, scop->sco_secname);
292 			}
293 		}
294 		if ((sgp->sg_flags & FLG_SG_KEY) == 0)
295 			continue;
296 
297 		for (APLIST_TRAVERSE(sgp->sg_osdescs, idx, osp)) {
298 			Listnode	*lnp2;
299 			Is_desc		*isp;
300 
301 			if ((osp->os_flags & FLG_OS_ORDER_KEY) == 0)
302 				continue;
303 
304 			for (LIST_TRAVERSE(&(osp->os_isdescs), lnp2, isp)) {
305 				if (isp->is_flags & FLG_IS_KEY)
306 					isp->is_key = key++;
307 			}
308 		}
309 	}
310 }
311 
312 static int
313 setup_sortbuf(Os_desc *osp)
314 {
315 	Sort_desc	*st = osp->os_sort;
316 	Word		num_after = 0, num_before = 0, num_order = 0;
317 	Listnode	*lnp1;
318 	Is_desc		*isp;
319 
320 	if ((st == NULL) ||
321 	    ((st->st_ordercnt + st->st_beforecnt + st->st_aftercnt) == 0))
322 		return (0);
323 
324 	/*
325 	 * Get memory
326 	 */
327 	if (st->st_beforecnt != 0) {
328 		if ((st->st_before =
329 		    libld_calloc(st->st_beforecnt, sizeof (Is_desc *))) == 0)
330 			return (0);
331 	}
332 	if (st->st_ordercnt != 0) {
333 		if ((st->st_order =
334 		    libld_calloc(st->st_ordercnt, sizeof (Is_desc *))) == 0)
335 			return (0);
336 	}
337 	if (st->st_aftercnt != 0) {
338 		if ((st->st_after =
339 		    libld_calloc(st->st_aftercnt, sizeof (Is_desc *))) == 0)
340 			return (0);
341 	}
342 
343 	/*
344 	 * Set info.
345 	 */
346 	for (LIST_TRAVERSE(&(osp->os_isdescs), lnp1, isp)) {
347 		Word	keylink = 0;
348 
349 		if ((isp->is_flags & FLG_IS_ORDERED) == 0)
350 			continue;
351 
352 		if (isp->is_shdr->sh_flags & SHF_ORDERED)
353 			keylink = isp->is_shdr->sh_info;
354 		else if (isp->is_shdr->sh_flags & SHF_LINK_ORDER)
355 			keylink = isp->is_shdr->sh_link;
356 
357 		if (keylink == SHN_BEFORE)
358 			st->st_before[num_before++] = isp;
359 		else if (keylink == SHN_AFTER)
360 			st->st_after[num_after++] = isp;
361 		else
362 			st->st_order[num_order++] = isp;
363 	}
364 	return (1);
365 }
366 
367 static int
368 comp(const void *ss1, const void *ss2)
369 {
370 	Is_desc		*s1 = *((Is_desc **)ss1);
371 	Is_desc		*s2 = *((Is_desc **)ss2);
372 	Is_desc		*i1, *i2;
373 	Word		ndx1, ndx2;
374 
375 	if (s1->is_shdr->sh_flags & SHF_ORDERED)  {
376 		ndx1 = s1->is_shdr->sh_info;
377 	} else {
378 		ndx1 = s1->is_shdr->sh_link;
379 	}
380 
381 	if (s2->is_shdr->sh_flags & SHF_ORDERED)  {
382 		ndx2 = s2->is_shdr->sh_info;
383 	} else {
384 		ndx2 = s2->is_shdr->sh_link;
385 	}
386 
387 	i1 = s1->is_file->ifl_isdesc[ndx1];
388 	i2 = s2->is_file->ifl_isdesc[ndx2];
389 
390 	if (i1->is_key > i2->is_key)
391 		return (1);
392 	if (i1->is_key < i2->is_key)
393 		return (-1);
394 	return (0);
395 }
396 
397 uintptr_t
398 ld_sort_ordered(Ofl_desc *ofl)
399 {
400 	Listnode *lnp1;
401 	Os_desc *osp;
402 
403 	DBG_CALL(Dbg_sec_order_list(ofl, 0));
404 
405 	/*
406 	 * Sort Sections
407 	 */
408 	for (LIST_TRAVERSE(&ofl->ofl_ordered, lnp1, osp)) {
409 		int		i;
410 		List		islist;
411 		Listnode *	lnp2;
412 		Is_desc *	isp;
413 		Sort_desc *	st = osp->os_sort;
414 
415 		if (setup_sortbuf(osp) == 0)
416 			return (S_ERROR);
417 
418 		islist = osp->os_isdescs;
419 		osp->os_isdescs.head = 0;
420 		osp->os_isdescs.tail = 0;
421 
422 		/*
423 		 * Sorting.
424 		 * First Sort the ordered sections.
425 		 */
426 		if (st->st_ordercnt != 0)
427 			qsort((char *)st->st_order, st->st_ordercnt,
428 			    sizeof (Is_desc *), comp);
429 
430 		/*
431 		 * Place SHN_BEFORE at head of list
432 		 */
433 		for (i = 0; i < st->st_beforecnt; i++) {
434 			if (ld_append_isp(ofl, osp, st->st_before[i], 0) == 0)
435 				return (S_ERROR);
436 		}
437 
438 		/*
439 		 * Next come 'linked' ordered sections
440 		 */
441 		for (i = 0; i < st->st_ordercnt; i++) {
442 			if (ld_append_isp(ofl, osp, st->st_order[i], 0) == 0)
443 				return (S_ERROR);
444 		}
445 
446 		/*
447 		 * Now we list any sections which have no sorting
448 		 * specifications - in the order they were input.
449 		 *
450 		 * We use list_appendc() here instead of ld_append_isp(),
451 		 * because these items have already been inserted once, and
452 		 * we don't want any duplicate entries in osp->os_mstridescs.
453 		 */
454 		for (LIST_TRAVERSE(&islist, lnp2, isp)) {
455 			if (isp->is_flags & FLG_IS_ORDERED)
456 				continue;
457 			if (list_appendc(&(osp->os_isdescs),
458 			    isp) == 0)
459 				return (S_ERROR);
460 		}
461 
462 		/*
463 		 * And the end of the list are the SHN_AFTER sections.
464 		 */
465 		for (i = 0; i < st->st_aftercnt; i++) {
466 			if (ld_append_isp(ofl, osp, st->st_after[i], 0) == 0)
467 				return (S_ERROR);
468 		}
469 	}
470 	DBG_CALL(Dbg_sec_order_list(ofl, 1));
471 	return (0);
472 }
473