order.c revision 1618:8c9a4f31d225
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 2006 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 */
45static Word
46is_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
68static Word
69get_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 */
151uintptr_t
152ld_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	keylink = 0;
170	if (shflags & SHF_ORDERED)
171		keylink = isp->is_shdr->sh_info;
172	else if (shflags & SHF_LINK_ORDER)
173		keylink = isp->is_shdr->sh_link;
174
175	if ((error = is_keylink_ok(ifl, keylink, limit)) != 0) {
176		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
177		isp->is_flags &= ~FLG_IS_ORDERED;
178		if (isp->is_osdesc == NULL)
179			return ((uintptr_t)ld_place_section(ofl, isp,
180			    isp->is_key, 0));
181		return ((uintptr_t)isp->is_osdesc);
182	}
183
184	/*
185	 * If SHF_ORDERED is in effect - the we search for
186	 * our desitination section based off of sh_link else
187	 * we follow the default rules for the desitination 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_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 = ld_place_section(ofl, isp, isp->is_ident,
211		    dest_ndx)) == (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(ofl->ofl_lml, ERR_FATAL,
249			    MSG_INTL(MSG_FIL_BADORDREF), ifl->ifl_name,
250			    isp->is_name, isp->is_scnndx, isp2->is_name,
251			    isp2->is_scnndx);
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 */
272void
273ld_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(ofl->ofl_lml, ERR_WARNING,
287				    MSG_INTL(MSG_MAP_SECORDER),
288				    sgp->sg_name, scop->sco_secname);
289
290		if ((sgp->sg_flags & FLG_SG_KEY) == 0)
291			continue;
292
293		for (LIST_TRAVERSE(&(sgp->sg_osdescs), lnp2, osp)) {
294			Listnode *	lnp3;
295			Is_desc *	isp;
296
297			if ((osp->os_flags & FLG_OS_ORDER_KEY) == 0)
298				continue;
299
300			for (LIST_TRAVERSE(&(osp->os_isdescs), lnp3, isp)) {
301				if (isp->is_flags & FLG_IS_KEY) {
302					isp->is_key = key++;
303				}
304			}
305		}
306	}
307}
308
309static int
310setup_sortbuf(Os_desc *osp)
311{
312	Sort_desc	*st = osp->os_sort;
313	Word		num_after = 0, num_before = 0, num_order = 0;
314	Listnode	*lnp1;
315	Is_desc		*isp;
316
317	if ((st == NULL) ||
318	    ((st->st_ordercnt + st->st_beforecnt + st->st_aftercnt) == 0))
319		return (0);
320
321	/*
322	 * Get memory
323	 */
324	if (st->st_beforecnt != 0) {
325		if ((st->st_before =
326		    libld_calloc(st->st_beforecnt, sizeof (Is_desc *))) == 0)
327			return (0);
328	}
329	if (st->st_ordercnt != 0) {
330		if ((st->st_order =
331		    libld_calloc(st->st_ordercnt, sizeof (Is_desc *))) == 0)
332			return (0);
333	}
334	if (st->st_aftercnt != 0) {
335		if ((st->st_after =
336		    libld_calloc(st->st_aftercnt, sizeof (Is_desc *))) == 0)
337			return (0);
338	}
339
340	/*
341	 * Set info.
342	 */
343	for (LIST_TRAVERSE(&(osp->os_isdescs), lnp1, isp)) {
344		Word	keylink = 0;
345
346		if ((isp->is_flags & FLG_IS_ORDERED) == 0)
347			continue;
348
349		if (isp->is_shdr->sh_flags & SHF_ORDERED)
350			keylink = isp->is_shdr->sh_info;
351		else if (isp->is_shdr->sh_flags & SHF_LINK_ORDER)
352			keylink = isp->is_shdr->sh_link;
353
354		if (keylink == SHN_BEFORE)
355			st->st_before[num_before++] = isp;
356		else if (keylink == SHN_AFTER)
357			st->st_after[num_after++] = isp;
358		else
359			st->st_order[num_order++] = isp;
360	}
361	return (1);
362}
363
364static int
365comp(const void *ss1, const void *ss2)
366{
367	Is_desc		*s1 = *((Is_desc **)ss1);
368	Is_desc		*s2 = *((Is_desc **)ss2);
369	Is_desc		*i1, *i2;
370	Word		ndx1, ndx2;
371
372	if (s1->is_shdr->sh_flags & SHF_ORDERED)  {
373		ndx1 = s1->is_shdr->sh_info;
374	} else {
375		ndx1 = s1->is_shdr->sh_link;
376	}
377
378	if (s2->is_shdr->sh_flags & SHF_ORDERED)  {
379		ndx2 = s2->is_shdr->sh_info;
380	} else {
381		ndx2 = s2->is_shdr->sh_link;
382	}
383
384	i1 = s1->is_file->ifl_isdesc[ndx1];
385	i2 = s2->is_file->ifl_isdesc[ndx2];
386
387	if (i1->is_key > i2->is_key)
388		return (1);
389	if (i1->is_key < i2->is_key)
390		return (-1);
391	return (0);
392}
393
394uintptr_t
395ld_sort_ordered(Ofl_desc *ofl)
396{
397	Listnode *lnp1;
398	Os_desc *osp;
399
400	DBG_CALL(Dbg_sec_order_list(ofl, 0));
401
402	/*
403	 * Sort Sections
404	 */
405	for (LIST_TRAVERSE(&ofl->ofl_ordered, lnp1, osp)) {
406		int		i;
407		List		islist;
408		Listnode *	lnp2;
409		Is_desc *	isp;
410		Sort_desc *	st = osp->os_sort;
411
412		if (setup_sortbuf(osp) == 0)
413			return (S_ERROR);
414
415		islist = osp->os_isdescs;
416		osp->os_isdescs.head = 0;
417		osp->os_isdescs.tail = 0;
418
419		/*
420		 * Sorting.
421		 * First Sort the ordered sections.
422		 */
423		if (st->st_ordercnt != 0)
424			qsort((char *)st->st_order, st->st_ordercnt,
425				sizeof (Is_desc *), comp);
426
427		/*
428		 * Place SHN_BEFORE at head of list
429		 */
430		for (i = 0; i < st->st_beforecnt; i++) {
431			if (list_appendc(&(osp->os_isdescs),
432			    st->st_before[i]) == 0)
433				return (S_ERROR);
434		}
435
436		/*
437		 * Next come 'linked' ordered sections
438		 */
439		for (i = 0; i < st->st_ordercnt; i++) {
440			if (list_appendc(&(osp->os_isdescs),
441			    st->st_order[i]) == 0)
442				return (S_ERROR);
443		}
444
445		/*
446		 * Now we list any sections which have no sorting
447		 * specifications - in the order they were input.
448		 */
449		for (LIST_TRAVERSE(&islist, lnp2, isp)) {
450			if (isp->is_flags & FLG_IS_ORDERED)
451				continue;
452			if (list_appendc(&(osp->os_isdescs),
453			    isp) == 0)
454				return (S_ERROR);
455		}
456
457		/*
458		 * And the end of the list are the SHN_AFTER sections.
459		 */
460		for (i = 0; i < st->st_aftercnt; i++) {
461			if (list_appendc(&(osp->os_isdescs),
462			    st->st_after[i]) == 0)
463				return (S_ERROR);
464		}
465	}
466	DBG_CALL(Dbg_sec_order_list(ofl, 1));
467	return (0);
468}
469