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