order.c revision 2647:e440e3da2a6f
1251881Speter/*
2251881Speter * CDDL HEADER START
3251881Speter *
4251881Speter * The contents of this file are subject to the terms of the
5251881Speter * Common Development and Distribution License (the "License").
6251881Speter * You may not use this file except in compliance with the License.
7251881Speter *
8251881Speter * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9251881Speter * or http://www.opensolaris.org/os/licensing.
10251881Speter * See the License for the specific language governing permissions
11251881Speter * and limitations under the License.
12251881Speter *
13251881Speter * When distributing Covered Code, include this CDDL HEADER in each
14251881Speter * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15251881Speter * If applicable, add the following below this CDDL HEADER, with the
16251881Speter * fields enclosed by brackets "[]" replaced with your own identifying
17251881Speter * information: Portions Copyright [yyyy] [name of copyright owner]
18251881Speter *
19251881Speter * CDDL HEADER END
20251881Speter */
21251881Speter
22251881Speter/*
23251881Speter * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24251881Speter * Use is subject to license terms.
25251881Speter */
26251881Speter
27251881Speter#pragma ident	"%Z%%M%	%I%	%E% SMI"
28251881Speter
29251881Speter/*
30251881Speter * Processing of SHF_ORDERED sections.
31251881Speter */
32251881Speter#include	<stdio.h>
33251881Speter#include	<fcntl.h>
34251881Speter#include	<link.h>
35251881Speter#include	<debug.h>
36251881Speter#include	"msg.h"
37251881Speter#include	"_libld.h"
38251881Speter
39251881Speter/*
40251881Speter * Part 1, Input processing.
41251881Speter */
42251881Speter/*
43251881Speter * Get the head section number
44251881Speter */
45251881Speterstatic Word
46251881Speteris_keylink_ok(Ifl_desc *ifl, Word keylink, Word limit)
47251881Speter{
48251881Speter	if ((keylink != SHN_BEFORE) && (keylink != SHN_AFTER)) {
49251881Speter		/*
50251881Speter		 * Range Check
51251881Speter		 */
52251881Speter		if ((keylink == 0) || (keylink >= limit)) {
53251881Speter			return (DBG_ORDER_LINK_OUTRANGE);
54251881Speter		}
55251881Speter
56251881Speter		/*
57251881Speter		 * The section pointed by keylink should not be an
58251881Speter		 * ordered section.
59251881Speter		 */
60251881Speter		if (ifl->ifl_isdesc[keylink]->is_shdr->sh_flags &
61251881Speter		    ALL_SHF_ORDER) {
62251881Speter			return (DBG_ORDER_INFO_ORDER);
63251881Speter		}
64251881Speter	}
65251881Speter	return (0);
66251881Speter}
67251881Speter
68251881Speterstatic Word
69251881Speterget_shfordered_dest(Ofl_desc *ofl, Ifl_desc *ifl, Word ndx, Word limit)
70251881Speter{
71251881Speter	Word t1_link = ndx, t2_link, ret_link;
72251881Speter	Is_desc *isp, *isp1, *isp2;
73251881Speter	int error = 0;
74251881Speter
75251881Speter	/*
76251881Speter	 * Check the sh_info of myself.
77251881Speter	 */
78251881Speter	isp = ifl->ifl_isdesc[ndx];
79251881Speter
80251881Speter	isp1 = isp;
81251881Speter	ret_link = t2_link = isp1->is_shdr->sh_link;
82251881Speter	t1_link = ndx;
83251881Speter	do {
84251881Speter		/*
85251881Speter		 * Check the validitiy of the link
86251881Speter		 */
87251881Speter		if (t2_link == 0 || t2_link >= limit) {
88251881Speter			error = DBG_ORDER_LINK_OUTRANGE;
89251881Speter			break;
90251881Speter		}
91251881Speter		isp2 = ifl->ifl_isdesc[t2_link];
92251881Speter
93251881Speter		/*
94251881Speter		 * Pointing to a bad ordered section ?
95251881Speter		 */
96251881Speter		if ((isp2->is_flags & FLG_IS_ORDERED) == 0) {
97251881Speter			error = DBG_ORDER_LINK_ERROR;
98251881Speter			break;
99251881Speter		}
100251881Speter
101251881Speter		/*
102251881Speter		 * Check sh_flag
103251881Speter		 */
104251881Speter		if (isp1->is_shdr->sh_flags != isp2->is_shdr->sh_flags) {
105251881Speter			error = DBG_ORDER_FLAGS;
106251881Speter			break;
107251881Speter		}
108251881Speter
109251881Speter		/*
110251881Speter		 * Check the validity of sh_info field.
111251881Speter		 */
112251881Speter		if ((error = is_keylink_ok(ifl,
113251881Speter		    isp->is_shdr->sh_info, limit)) != 0) {
114251881Speter			break;
115251881Speter		}
116251881Speter
117251881Speter		/*
118251881Speter		 * Can I break ?
119251881Speter		 */
120251881Speter		if (t1_link == t2_link)
121251881Speter			break;
122251881Speter
123251881Speter		/*
124251881Speter		 * Get the next link
125251881Speter		 */
126251881Speter		t1_link = t2_link;
127251881Speter		isp1 = ifl->ifl_isdesc[t1_link];
128251881Speter		ret_link = t2_link = isp1->is_shdr->sh_link;
129251881Speter
130251881Speter		/*
131251881Speter		 * Cyclic ?
132251881Speter		 */
133251881Speter		if (t2_link == ndx) {
134251881Speter			error = DBG_ORDER_CYCLIC;
135251881Speter			break;
136251881Speter		}
137251881Speter	/* CONSTANTCONDITION */
138251881Speter	} while (1);
139251881Speter
140251881Speter	if (error != 0) {
141251881Speter		ret_link = 0;
142251881Speter		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
143251881Speter	}
144251881Speter	return (ret_link);
145251881Speter}
146251881Speter
147251881Speter/*
148251881Speter * Called from process_elf().
149251881Speter * This routine does the input processing of the ordered sections.
150251881Speter */
151251881Speteruintptr_t
152251881Speterld_process_ordered(Ifl_desc *ifl, Ofl_desc *ofl, Word ndx, Word limit)
153251881Speter{
154251881Speter	Is_desc *	isp2, * isp = ifl->ifl_isdesc[ndx];
155251881Speter	Xword		shflags = isp->is_shdr->sh_flags;
156251881Speter	uint_t		keylink;
157251881Speter	Os_desc *	osp2, * osp;
158251881Speter	Word		dest_ndx;
159251881Speter	Sort_desc *	st;
160251881Speter	Listnode *	lnp;
161251881Speter	int		error = 0;
162251881Speter
163251881Speter	/*
164251881Speter	 * I might have been checked and marked error already.
165251881Speter	 */
166251881Speter	if ((isp->is_flags & FLG_IS_ORDERED) == 0)
167251881Speter		return (0);
168251881Speter
169251881Speter	if (shflags & SHF_ORDERED)
170251881Speter		keylink = isp->is_shdr->sh_info;
171251881Speter	else if (shflags & SHF_LINK_ORDER)
172251881Speter		keylink = isp->is_shdr->sh_link;
173251881Speter	else
174251881Speter		keylink = 0;
175251881Speter
176251881Speter	if ((error = is_keylink_ok(ifl, keylink, limit)) != 0) {
177251881Speter		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
178251881Speter		isp->is_flags &= ~FLG_IS_ORDERED;
179251881Speter		if (isp->is_osdesc == NULL)
180251881Speter			return ((uintptr_t)ld_place_section(ofl, isp,
181251881Speter			    isp->is_key, 0));
182251881Speter		return ((uintptr_t)isp->is_osdesc);
183251881Speter	}
184251881Speter
185251881Speter	/*
186251881Speter	 * If SHF_ORDERED is in effect, search for our destination section based
187251881Speter	 * off of sh_link, otherwise follow the default rules for the
188251881Speter	 * destination section.
189251881Speter	 */
190251881Speter	if (shflags & SHF_ORDERED) {
191251881Speter		if ((dest_ndx = get_shfordered_dest(ofl, ifl,
192251881Speter		    ndx, limit)) == 0) {
193251881Speter			isp->is_flags &= ~FLG_IS_ORDERED;
194251881Speter			if (isp->is_osdesc == NULL)
195251881Speter				return ((uintptr_t)ld_place_section(ofl, isp,
196251881Speter				    isp->is_key, 0));
197251881Speter			return ((uintptr_t)isp->is_osdesc);
198251881Speter		}
199251881Speter	} else {
200251881Speter		/*
201251881Speter		 * SHF_LINK_ORDER coalesces into default sections, set dest_ndx
202251881Speter		 * to NULL to trigger this.
203251881Speter		 */
204251881Speter		dest_ndx = 0;
205251881Speter	}
206251881Speter
207251881Speter	/*
208251881Speter	 * Place the section into it's output section.
209251881Speter	 */
210251881Speter	if ((osp = isp->is_osdesc) == NULL) {
211251881Speter		if ((osp = ld_place_section(ofl, isp, isp->is_ident,
212251881Speter		    dest_ndx)) == (Os_desc *)S_ERROR)
213251881Speter			return ((uintptr_t)S_ERROR);
214251881Speter		if (!osp)
215251881Speter			return (0);
216251881Speter	}
217251881Speter
218251881Speter	/*
219251881Speter	 * If the output section is not yet on the ordered
220251881Speter	 * list - place it on the list.
221251881Speter	 */
222251881Speter	osp2 = NULL;
223251881Speter	for (LIST_TRAVERSE(&ofl->ofl_ordered, lnp, osp2)) {
224251881Speter		if (osp2 == osp)
225251881Speter			break;
226251881Speter	}
227251881Speter
228251881Speter	if (osp != osp2) {
229251881Speter		if (list_appendc(&(ofl->ofl_ordered), osp) == 0)
230251881Speter			return ((uintptr_t)S_ERROR);
231251881Speter	}
232251881Speter
233251881Speter	/*
234251881Speter	 * Output section has been found - set up it's
235251881Speter	 * sorting information.
236251881Speter	 */
237251881Speter	if (osp->os_sort == 0) {
238251881Speter		if ((osp->os_sort = libld_calloc(1, sizeof (Sort_desc))) == 0)
239251881Speter			return (S_ERROR);
240251881Speter	}
241251881Speter	st = osp->os_sort;
242251881Speter
243251881Speter	if (keylink == SHN_BEFORE) {
244251881Speter		st->st_beforecnt++;
245251881Speter	} else if (keylink == SHN_AFTER) {
246251881Speter		st->st_aftercnt++;
247251881Speter	} else {
248251881Speter		st->st_ordercnt++;
249251881Speter		isp2 = ifl->ifl_isdesc[keylink];
250251881Speter		if (isp2->is_flags & FLG_IS_DISCARD) {
251251881Speter			eprintf(ofl->ofl_lml, ERR_FATAL,
252251881Speter			    MSG_INTL(MSG_FIL_BADORDREF), ifl->ifl_name,
253251881Speter			    isp->is_name, isp->is_scnndx, isp2->is_name,
254251881Speter			    isp2->is_scnndx);
255251881Speter			return (S_ERROR);
256251881Speter		}
257251881Speter		osp2 = isp2->is_osdesc;
258251881Speter		osp2->os_flags |= FLG_OS_ORDER_KEY;
259251881Speter		osp2->os_sgdesc->sg_flags |= FLG_SG_KEY;
260251881Speter		isp2->is_flags |= FLG_IS_KEY;
261251881Speter	}
262251881Speter
263251881Speter	return ((uintptr_t)osp);
264251881Speter}
265251881Speter
266251881Speter/*
267251881Speter * Part 2, Sorting processing
268251881Speter */
269251881Speter
270251881Speter/*
271251881Speter * Traverse all segments looking for section ordering information that hasn't
272251881Speter * been used.  If found give a warning message to the user.  Also, check if
273251881Speter * there are any SHF_ORDERED key sections, and if so set up sort key values.
274251881Speter */
275251881Spetervoid
276251881Speterld_sec_validate(Ofl_desc *ofl)
277251881Speter{
278251881Speter	Listnode	*lnp1;
279251881Speter	Sg_desc		*sgp;
280251881Speter	int 		key = 1;
281251881Speter
282251881Speter	for (LIST_TRAVERSE(&ofl->ofl_segs, lnp1, sgp)) {
283251881Speter		Sec_order	**scopp;
284251881Speter		Os_desc		**ospp;
285251881Speter		Aliste		off;
286251881Speter
287251881Speter		for (ALIST_TRAVERSE(sgp->sg_secorder, off, scopp)) {
288251881Speter			Sec_order	*scop = *scopp;
289251881Speter
290251881Speter			if ((scop->sco_flags & FLG_SGO_USED) == 0) {
291251881Speter				eprintf(ofl->ofl_lml, ERR_WARNING,
292251881Speter				    MSG_INTL(MSG_MAP_SECORDER),
293251881Speter				    sgp->sg_name, scop->sco_secname);
294251881Speter			}
295251881Speter		}
296251881Speter		if ((sgp->sg_flags & FLG_SG_KEY) == 0)
297251881Speter			continue;
298251881Speter
299251881Speter		for (ALIST_TRAVERSE(sgp->sg_osdescs, off, ospp)) {
300251881Speter			Listnode	*lnp2;
301251881Speter			Is_desc		*isp;
302251881Speter			Os_desc		*osp = *ospp;
303251881Speter
304251881Speter			if ((osp->os_flags & FLG_OS_ORDER_KEY) == 0)
305251881Speter				continue;
306251881Speter
307251881Speter			for (LIST_TRAVERSE(&(osp->os_isdescs), lnp2, isp)) {
308251881Speter				if (isp->is_flags & FLG_IS_KEY)
309251881Speter					isp->is_key = key++;
310251881Speter			}
311251881Speter		}
312251881Speter	}
313251881Speter}
314251881Speter
315251881Speterstatic int
316251881Spetersetup_sortbuf(Os_desc *osp)
317251881Speter{
318251881Speter	Sort_desc	*st = osp->os_sort;
319251881Speter	Word		num_after = 0, num_before = 0, num_order = 0;
320251881Speter	Listnode	*lnp1;
321251881Speter	Is_desc		*isp;
322251881Speter
323251881Speter	if ((st == NULL) ||
324251881Speter	    ((st->st_ordercnt + st->st_beforecnt + st->st_aftercnt) == 0))
325251881Speter		return (0);
326251881Speter
327251881Speter	/*
328251881Speter	 * Get memory
329251881Speter	 */
330251881Speter	if (st->st_beforecnt != 0) {
331251881Speter		if ((st->st_before =
332251881Speter		    libld_calloc(st->st_beforecnt, sizeof (Is_desc *))) == 0)
333251881Speter			return (0);
334251881Speter	}
335251881Speter	if (st->st_ordercnt != 0) {
336251881Speter		if ((st->st_order =
337251881Speter		    libld_calloc(st->st_ordercnt, sizeof (Is_desc *))) == 0)
338251881Speter			return (0);
339251881Speter	}
340251881Speter	if (st->st_aftercnt != 0) {
341251881Speter		if ((st->st_after =
342251881Speter		    libld_calloc(st->st_aftercnt, sizeof (Is_desc *))) == 0)
343251881Speter			return (0);
344251881Speter	}
345251881Speter
346251881Speter	/*
347251881Speter	 * Set info.
348251881Speter	 */
349251881Speter	for (LIST_TRAVERSE(&(osp->os_isdescs), lnp1, isp)) {
350251881Speter		Word	keylink = 0;
351251881Speter
352251881Speter		if ((isp->is_flags & FLG_IS_ORDERED) == 0)
353251881Speter			continue;
354251881Speter
355251881Speter		if (isp->is_shdr->sh_flags & SHF_ORDERED)
356251881Speter			keylink = isp->is_shdr->sh_info;
357251881Speter		else if (isp->is_shdr->sh_flags & SHF_LINK_ORDER)
358251881Speter			keylink = isp->is_shdr->sh_link;
359251881Speter
360251881Speter		if (keylink == SHN_BEFORE)
361251881Speter			st->st_before[num_before++] = isp;
362251881Speter		else if (keylink == SHN_AFTER)
363251881Speter			st->st_after[num_after++] = isp;
364251881Speter		else
365251881Speter			st->st_order[num_order++] = isp;
366251881Speter	}
367251881Speter	return (1);
368251881Speter}
369253734Speter
370251881Speterstatic int
371251881Spetercomp(const void *ss1, const void *ss2)
372251881Speter{
373251881Speter	Is_desc		*s1 = *((Is_desc **)ss1);
374251881Speter	Is_desc		*s2 = *((Is_desc **)ss2);
375251881Speter	Is_desc		*i1, *i2;
376	Word		ndx1, ndx2;
377
378	if (s1->is_shdr->sh_flags & SHF_ORDERED)  {
379		ndx1 = s1->is_shdr->sh_info;
380	} else {
381		ndx1 = s1->is_shdr->sh_link;
382	}
383
384	if (s2->is_shdr->sh_flags & SHF_ORDERED)  {
385		ndx2 = s2->is_shdr->sh_info;
386	} else {
387		ndx2 = s2->is_shdr->sh_link;
388	}
389
390	i1 = s1->is_file->ifl_isdesc[ndx1];
391	i2 = s2->is_file->ifl_isdesc[ndx2];
392
393	if (i1->is_key > i2->is_key)
394		return (1);
395	if (i1->is_key < i2->is_key)
396		return (-1);
397	return (0);
398}
399
400uintptr_t
401ld_sort_ordered(Ofl_desc *ofl)
402{
403	Listnode *lnp1;
404	Os_desc *osp;
405
406	DBG_CALL(Dbg_sec_order_list(ofl, 0));
407
408	/*
409	 * Sort Sections
410	 */
411	for (LIST_TRAVERSE(&ofl->ofl_ordered, lnp1, osp)) {
412		int		i;
413		List		islist;
414		Listnode *	lnp2;
415		Is_desc *	isp;
416		Sort_desc *	st = osp->os_sort;
417
418		if (setup_sortbuf(osp) == 0)
419			return (S_ERROR);
420
421		islist = osp->os_isdescs;
422		osp->os_isdescs.head = 0;
423		osp->os_isdescs.tail = 0;
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 (list_appendc(&(osp->os_isdescs),
438			    st->st_before[i]) == 0)
439				return (S_ERROR);
440		}
441
442		/*
443		 * Next come 'linked' ordered sections
444		 */
445		for (i = 0; i < st->st_ordercnt; i++) {
446			if (list_appendc(&(osp->os_isdescs),
447			    st->st_order[i]) == 0)
448				return (S_ERROR);
449		}
450
451		/*
452		 * Now we list any sections which have no sorting
453		 * specifications - in the order they were input.
454		 */
455		for (LIST_TRAVERSE(&islist, lnp2, isp)) {
456			if (isp->is_flags & FLG_IS_ORDERED)
457				continue;
458			if (list_appendc(&(osp->os_isdescs),
459			    isp) == 0)
460				return (S_ERROR);
461		}
462
463		/*
464		 * And the end of the list are the SHN_AFTER sections.
465		 */
466		for (i = 0; i < st->st_aftercnt; i++) {
467			if (list_appendc(&(osp->os_isdescs),
468			    st->st_after[i]) == 0)
469				return (S_ERROR);
470		}
471	}
472	DBG_CALL(Dbg_sec_order_list(ofl, 1));
473	return (0);
474}
475