xref: /illumos-gate/usr/src/cmd/sgs/libld/common/order.c (revision 0e233487902b546a8949e2147ff8af45b1afc77c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215aefb655Srie 
227c478bd9Sstevel@tonic-gate /*
23cce0e03bSab196087  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Processing of SHF_ORDERED sections.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate #include	<stdio.h>
317c478bd9Sstevel@tonic-gate #include	<fcntl.h>
327c478bd9Sstevel@tonic-gate #include	<link.h>
335aefb655Srie #include	<debug.h>
347c478bd9Sstevel@tonic-gate #include	"msg.h"
357c478bd9Sstevel@tonic-gate #include	"_libld.h"
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate  * Part 1, Input processing.
397c478bd9Sstevel@tonic-gate  */
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * Get the head section number
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate static Word
447c478bd9Sstevel@tonic-gate is_keylink_ok(Ifl_desc *ifl, Word keylink, Word limit)
457c478bd9Sstevel@tonic-gate {
467c478bd9Sstevel@tonic-gate 	if ((keylink != SHN_BEFORE) && (keylink != SHN_AFTER)) {
477c478bd9Sstevel@tonic-gate 		/*
487c478bd9Sstevel@tonic-gate 		 * Range Check
497c478bd9Sstevel@tonic-gate 		 */
507c478bd9Sstevel@tonic-gate 		if ((keylink == 0) || (keylink >= limit)) {
517c478bd9Sstevel@tonic-gate 			return (DBG_ORDER_LINK_OUTRANGE);
527c478bd9Sstevel@tonic-gate 		}
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate 		/*
557c478bd9Sstevel@tonic-gate 		 * The section pointed by keylink should not be an
567c478bd9Sstevel@tonic-gate 		 * ordered section.
577c478bd9Sstevel@tonic-gate 		 */
587c478bd9Sstevel@tonic-gate 		if (ifl->ifl_isdesc[keylink]->is_shdr->sh_flags &
597c478bd9Sstevel@tonic-gate 		    ALL_SHF_ORDER) {
607c478bd9Sstevel@tonic-gate 			return (DBG_ORDER_INFO_ORDER);
617c478bd9Sstevel@tonic-gate 		}
627c478bd9Sstevel@tonic-gate 	}
637c478bd9Sstevel@tonic-gate 	return (0);
647c478bd9Sstevel@tonic-gate }
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static Word
675aefb655Srie get_shfordered_dest(Ofl_desc *ofl, Ifl_desc *ifl, Word ndx, Word limit)
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate 	Word t1_link = ndx, t2_link, ret_link;
707c478bd9Sstevel@tonic-gate 	Is_desc *isp, *isp1, *isp2;
717c478bd9Sstevel@tonic-gate 	int error = 0;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	/*
747c478bd9Sstevel@tonic-gate 	 * Check the sh_info of myself.
757c478bd9Sstevel@tonic-gate 	 */
767c478bd9Sstevel@tonic-gate 	isp = ifl->ifl_isdesc[ndx];
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	isp1 = isp;
797c478bd9Sstevel@tonic-gate 	ret_link = t2_link = isp1->is_shdr->sh_link;
807c478bd9Sstevel@tonic-gate 	t1_link = ndx;
817c478bd9Sstevel@tonic-gate 	do {
827c478bd9Sstevel@tonic-gate 		/*
837c478bd9Sstevel@tonic-gate 		 * Check the validitiy of the link
847c478bd9Sstevel@tonic-gate 		 */
857c478bd9Sstevel@tonic-gate 		if (t2_link == 0 || t2_link >= limit) {
867c478bd9Sstevel@tonic-gate 			error = DBG_ORDER_LINK_OUTRANGE;
877c478bd9Sstevel@tonic-gate 			break;
887c478bd9Sstevel@tonic-gate 		}
897c478bd9Sstevel@tonic-gate 		isp2 = ifl->ifl_isdesc[t2_link];
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 		/*
927c478bd9Sstevel@tonic-gate 		 * Pointing to a bad ordered section ?
937c478bd9Sstevel@tonic-gate 		 */
947c478bd9Sstevel@tonic-gate 		if ((isp2->is_flags & FLG_IS_ORDERED) == 0) {
957c478bd9Sstevel@tonic-gate 			error = DBG_ORDER_LINK_ERROR;
967c478bd9Sstevel@tonic-gate 			break;
977c478bd9Sstevel@tonic-gate 		}
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 		/*
1007c478bd9Sstevel@tonic-gate 		 * Check sh_flag
1017c478bd9Sstevel@tonic-gate 		 */
1027c478bd9Sstevel@tonic-gate 		if (isp1->is_shdr->sh_flags != isp2->is_shdr->sh_flags) {
1037c478bd9Sstevel@tonic-gate 			error = DBG_ORDER_FLAGS;
1047c478bd9Sstevel@tonic-gate 			break;
1057c478bd9Sstevel@tonic-gate 		}
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 		/*
1087c478bd9Sstevel@tonic-gate 		 * Check the validity of sh_info field.
1097c478bd9Sstevel@tonic-gate 		 */
1107c478bd9Sstevel@tonic-gate 		if ((error = is_keylink_ok(ifl,
1117c478bd9Sstevel@tonic-gate 		    isp->is_shdr->sh_info, limit)) != 0) {
1127c478bd9Sstevel@tonic-gate 			break;
1137c478bd9Sstevel@tonic-gate 		}
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 		/*
1167c478bd9Sstevel@tonic-gate 		 * Can I break ?
1177c478bd9Sstevel@tonic-gate 		 */
1187c478bd9Sstevel@tonic-gate 		if (t1_link == t2_link)
1197c478bd9Sstevel@tonic-gate 			break;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 		/*
1227c478bd9Sstevel@tonic-gate 		 * Get the next link
1237c478bd9Sstevel@tonic-gate 		 */
1247c478bd9Sstevel@tonic-gate 		t1_link = t2_link;
1257c478bd9Sstevel@tonic-gate 		isp1 = ifl->ifl_isdesc[t1_link];
1267c478bd9Sstevel@tonic-gate 		ret_link = t2_link = isp1->is_shdr->sh_link;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 		/*
1297c478bd9Sstevel@tonic-gate 		 * Cyclic ?
1307c478bd9Sstevel@tonic-gate 		 */
1317c478bd9Sstevel@tonic-gate 		if (t2_link == ndx) {
1327c478bd9Sstevel@tonic-gate 			error = DBG_ORDER_CYCLIC;
1337c478bd9Sstevel@tonic-gate 			break;
1347c478bd9Sstevel@tonic-gate 		}
1357c478bd9Sstevel@tonic-gate 	/* CONSTANTCONDITION */
1367c478bd9Sstevel@tonic-gate 	} while (1);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (error != 0) {
1397c478bd9Sstevel@tonic-gate 		ret_link = 0;
1405aefb655Srie 		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate 	return (ret_link);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate  * Called from process_elf().
1477c478bd9Sstevel@tonic-gate  * This routine does the input processing of the ordered sections.
1487c478bd9Sstevel@tonic-gate  */
1497c478bd9Sstevel@tonic-gate uintptr_t
1505aefb655Srie ld_process_ordered(Ifl_desc *ifl, Ofl_desc *ofl, Word ndx, Word limit)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	Is_desc *	isp2, * isp = ifl->ifl_isdesc[ndx];
1537c478bd9Sstevel@tonic-gate 	Xword		shflags = isp->is_shdr->sh_flags;
1547c478bd9Sstevel@tonic-gate 	uint_t		keylink;
1557c478bd9Sstevel@tonic-gate 	Os_desc *	osp2, * osp;
1567c478bd9Sstevel@tonic-gate 	Word		dest_ndx;
1577c478bd9Sstevel@tonic-gate 	Sort_desc *	st;
1587c478bd9Sstevel@tonic-gate 	Listnode *	lnp;
1597c478bd9Sstevel@tonic-gate 	int		error = 0;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	/*
1627c478bd9Sstevel@tonic-gate 	 * I might have been checked and marked error already.
1637c478bd9Sstevel@tonic-gate 	 */
1647c478bd9Sstevel@tonic-gate 	if ((isp->is_flags & FLG_IS_ORDERED) == 0)
1657c478bd9Sstevel@tonic-gate 		return (0);
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	if (shflags & SHF_ORDERED)
1687c478bd9Sstevel@tonic-gate 		keylink = isp->is_shdr->sh_info;
1697c478bd9Sstevel@tonic-gate 	else if (shflags & SHF_LINK_ORDER)
1707c478bd9Sstevel@tonic-gate 		keylink = isp->is_shdr->sh_link;
1717010c12aSrie 	else
1727010c12aSrie 		keylink = 0;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	if ((error = is_keylink_ok(ifl, keylink, limit)) != 0) {
1755aefb655Srie 		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
1767c478bd9Sstevel@tonic-gate 		isp->is_flags &= ~FLG_IS_ORDERED;
177*0e233487SRod Evans 		if (isp->is_osdesc == NULL) {
1785aefb655Srie 			return ((uintptr_t)ld_place_section(ofl, isp,
179*0e233487SRod Evans 			    isp->is_keyident, 0));
180*0e233487SRod Evans 		}
1817c478bd9Sstevel@tonic-gate 		return ((uintptr_t)isp->is_osdesc);
1827c478bd9Sstevel@tonic-gate 	}
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	/*
1857010c12aSrie 	 * If SHF_ORDERED is in effect, search for our destination section based
1867010c12aSrie 	 * off of sh_link, otherwise follow the default rules for the
1877010c12aSrie 	 * destination section.
1887c478bd9Sstevel@tonic-gate 	 */
1897c478bd9Sstevel@tonic-gate 	if (shflags & SHF_ORDERED) {
1905aefb655Srie 		if ((dest_ndx = get_shfordered_dest(ofl, ifl,
1915aefb655Srie 		    ndx, limit)) == 0) {
1927c478bd9Sstevel@tonic-gate 			isp->is_flags &= ~FLG_IS_ORDERED;
193*0e233487SRod Evans 			if (isp->is_osdesc == NULL) {
1945aefb655Srie 				return ((uintptr_t)ld_place_section(ofl, isp,
195*0e233487SRod Evans 				    isp->is_keyident, 0));
196*0e233487SRod Evans 			}
1977c478bd9Sstevel@tonic-gate 			return ((uintptr_t)isp->is_osdesc);
1987c478bd9Sstevel@tonic-gate 		}
1997c478bd9Sstevel@tonic-gate 	} else {
2007c478bd9Sstevel@tonic-gate 		/*
2017010c12aSrie 		 * SHF_LINK_ORDER coalesces into default sections, set dest_ndx
2027010c12aSrie 		 * to NULL to trigger this.
2037c478bd9Sstevel@tonic-gate 		 */
2047c478bd9Sstevel@tonic-gate 		dest_ndx = 0;
2057c478bd9Sstevel@tonic-gate 	}
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	/*
2087c478bd9Sstevel@tonic-gate 	 * Place the section into it's output section.
2097c478bd9Sstevel@tonic-gate 	 */
2107c478bd9Sstevel@tonic-gate 	if ((osp = isp->is_osdesc) == NULL) {
211*0e233487SRod Evans 		if ((osp = ld_place_section(ofl, isp, isp->is_keyident,
2125aefb655Srie 		    dest_ndx)) == (Os_desc *)S_ERROR)
2137c478bd9Sstevel@tonic-gate 			return ((uintptr_t)S_ERROR);
2147c478bd9Sstevel@tonic-gate 		if (!osp)
2157c478bd9Sstevel@tonic-gate 			return (0);
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	/*
2197c478bd9Sstevel@tonic-gate 	 * If the output section is not yet on the ordered
2207c478bd9Sstevel@tonic-gate 	 * list - place it on the list.
2217c478bd9Sstevel@tonic-gate 	 */
2227c478bd9Sstevel@tonic-gate 	osp2 = NULL;
2237010c12aSrie 	for (LIST_TRAVERSE(&ofl->ofl_ordered, lnp, osp2)) {
2247c478bd9Sstevel@tonic-gate 		if (osp2 == osp)
2257c478bd9Sstevel@tonic-gate 			break;
2267010c12aSrie 	}
2277c478bd9Sstevel@tonic-gate 
2287010c12aSrie 	if (osp != osp2) {
2297c478bd9Sstevel@tonic-gate 		if (list_appendc(&(ofl->ofl_ordered), osp) == 0)
2307c478bd9Sstevel@tonic-gate 			return ((uintptr_t)S_ERROR);
2317010c12aSrie 	}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	/*
2347c478bd9Sstevel@tonic-gate 	 * Output section has been found - set up it's
2357c478bd9Sstevel@tonic-gate 	 * sorting information.
2367c478bd9Sstevel@tonic-gate 	 */
2377c478bd9Sstevel@tonic-gate 	if (osp->os_sort == 0) {
2387c478bd9Sstevel@tonic-gate 		if ((osp->os_sort = libld_calloc(1, sizeof (Sort_desc))) == 0)
2397c478bd9Sstevel@tonic-gate 			return (S_ERROR);
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 	st = osp->os_sort;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	if (keylink == SHN_BEFORE) {
2447c478bd9Sstevel@tonic-gate 		st->st_beforecnt++;
2457c478bd9Sstevel@tonic-gate 	} else if (keylink == SHN_AFTER) {
2467c478bd9Sstevel@tonic-gate 		st->st_aftercnt++;
2477c478bd9Sstevel@tonic-gate 	} else {
2487c478bd9Sstevel@tonic-gate 		st->st_ordercnt++;
2497c478bd9Sstevel@tonic-gate 		isp2 = ifl->ifl_isdesc[keylink];
2507c478bd9Sstevel@tonic-gate 		if (isp2->is_flags & FLG_IS_DISCARD) {
2515aefb655Srie 			eprintf(ofl->ofl_lml, ERR_FATAL,
2525aefb655Srie 			    MSG_INTL(MSG_FIL_BADORDREF), ifl->ifl_name,
2535aefb655Srie 			    isp->is_name, isp->is_scnndx, isp2->is_name,
2545aefb655Srie 			    isp2->is_scnndx);
2557c478bd9Sstevel@tonic-gate 			return (S_ERROR);
2567c478bd9Sstevel@tonic-gate 		}
257*0e233487SRod Evans 
258*0e233487SRod Evans 		/*
259*0e233487SRod Evans 		 * Indicate that this ordered input section will require a sort
260*0e233487SRod Evans 		 * key created.  Propagate the key requirement through to the
261*0e233487SRod Evans 		 * associated output section, segment and file, to trigger the
262*0e233487SRod Evans 		 * sort key creation.  See ld_sec_validate();
263*0e233487SRod Evans 		 */
2647c478bd9Sstevel@tonic-gate 		isp2->is_flags |= FLG_IS_KEY;
265*0e233487SRod Evans 
266*0e233487SRod Evans 		osp2 = isp2->is_osdesc;
267*0e233487SRod Evans 		osp2->os_flags |= FLG_OS_KEY;
268*0e233487SRod Evans 		osp2->os_sgdesc->sg_flags |= FLG_SG_KEY;
269*0e233487SRod Evans 
270*0e233487SRod Evans 		ofl->ofl_flags |= FLG_OF_KEY;
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	return ((uintptr_t)osp);
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate /*
2777c478bd9Sstevel@tonic-gate  * Part 2, Sorting processing
2787c478bd9Sstevel@tonic-gate  */
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate /*
2817c478bd9Sstevel@tonic-gate  * Traverse all segments looking for section ordering information that hasn't
2827c478bd9Sstevel@tonic-gate  * been used.  If found give a warning message to the user.  Also, check if
2837c478bd9Sstevel@tonic-gate  * there are any SHF_ORDERED key sections, and if so set up sort key values.
2847c478bd9Sstevel@tonic-gate  */
2857c478bd9Sstevel@tonic-gate void
2865aefb655Srie ld_sec_validate(Ofl_desc *ofl)
2877c478bd9Sstevel@tonic-gate {
2887c478bd9Sstevel@tonic-gate 	Listnode	*lnp1;
2897c478bd9Sstevel@tonic-gate 	Sg_desc		*sgp;
290*0e233487SRod Evans 	Word 		key = 1;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ofl->ofl_segs, lnp1, sgp)) {
293cce0e03bSab196087 		Sec_order	*scop;
294cce0e03bSab196087 		Os_desc		*osp;
295cce0e03bSab196087 		Aliste		idx;
2967c478bd9Sstevel@tonic-gate 
297cce0e03bSab196087 		for (APLIST_TRAVERSE(sgp->sg_secorder, idx, scop)) {
2980bc07c75Srie 			if ((scop->sco_flags & FLG_SGO_USED) == 0) {
2995aefb655Srie 				eprintf(ofl->ofl_lml, ERR_WARNING,
3005aefb655Srie 				    MSG_INTL(MSG_MAP_SECORDER),
3017c478bd9Sstevel@tonic-gate 				    sgp->sg_name, scop->sco_secname);
3020bc07c75Srie 			}
3030bc07c75Srie 		}
3047c478bd9Sstevel@tonic-gate 		if ((sgp->sg_flags & FLG_SG_KEY) == 0)
3057c478bd9Sstevel@tonic-gate 			continue;
3067c478bd9Sstevel@tonic-gate 
307cce0e03bSab196087 		for (APLIST_TRAVERSE(sgp->sg_osdescs, idx, osp)) {
3080bc07c75Srie 			Listnode	*lnp2;
3097c478bd9Sstevel@tonic-gate 			Is_desc		*isp;
3107c478bd9Sstevel@tonic-gate 
311*0e233487SRod Evans 			if ((osp->os_flags & FLG_OS_KEY) == 0)
3127c478bd9Sstevel@tonic-gate 				continue;
3137c478bd9Sstevel@tonic-gate 
3140bc07c75Srie 			for (LIST_TRAVERSE(&(osp->os_isdescs), lnp2, isp)) {
3150bc07c75Srie 				if (isp->is_flags & FLG_IS_KEY)
316*0e233487SRod Evans 					isp->is_keyident = key++;
3177c478bd9Sstevel@tonic-gate 			}
3187c478bd9Sstevel@tonic-gate 		}
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate static int
3237c478bd9Sstevel@tonic-gate setup_sortbuf(Os_desc *osp)
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate 	Sort_desc	*st = osp->os_sort;
3267c478bd9Sstevel@tonic-gate 	Word		num_after = 0, num_before = 0, num_order = 0;
3277c478bd9Sstevel@tonic-gate 	Listnode	*lnp1;
3287c478bd9Sstevel@tonic-gate 	Is_desc		*isp;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if ((st == NULL) ||
3317c478bd9Sstevel@tonic-gate 	    ((st->st_ordercnt + st->st_beforecnt + st->st_aftercnt) == 0))
3327c478bd9Sstevel@tonic-gate 		return (0);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	/*
3357c478bd9Sstevel@tonic-gate 	 * Get memory
3367c478bd9Sstevel@tonic-gate 	 */
3377c478bd9Sstevel@tonic-gate 	if (st->st_beforecnt != 0) {
3387c478bd9Sstevel@tonic-gate 		if ((st->st_before =
3397c478bd9Sstevel@tonic-gate 		    libld_calloc(st->st_beforecnt, sizeof (Is_desc *))) == 0)
3407c478bd9Sstevel@tonic-gate 			return (0);
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 	if (st->st_ordercnt != 0) {
3437c478bd9Sstevel@tonic-gate 		if ((st->st_order =
3447c478bd9Sstevel@tonic-gate 		    libld_calloc(st->st_ordercnt, sizeof (Is_desc *))) == 0)
3457c478bd9Sstevel@tonic-gate 			return (0);
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 	if (st->st_aftercnt != 0) {
3487c478bd9Sstevel@tonic-gate 		if ((st->st_after =
3497c478bd9Sstevel@tonic-gate 		    libld_calloc(st->st_aftercnt, sizeof (Is_desc *))) == 0)
3507c478bd9Sstevel@tonic-gate 			return (0);
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	/*
3547c478bd9Sstevel@tonic-gate 	 * Set info.
3557c478bd9Sstevel@tonic-gate 	 */
3567c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&(osp->os_isdescs), lnp1, isp)) {
3577c478bd9Sstevel@tonic-gate 		Word	keylink = 0;
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 		if ((isp->is_flags & FLG_IS_ORDERED) == 0)
3607c478bd9Sstevel@tonic-gate 			continue;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 		if (isp->is_shdr->sh_flags & SHF_ORDERED)
3637c478bd9Sstevel@tonic-gate 			keylink = isp->is_shdr->sh_info;
3647c478bd9Sstevel@tonic-gate 		else if (isp->is_shdr->sh_flags & SHF_LINK_ORDER)
3657c478bd9Sstevel@tonic-gate 			keylink = isp->is_shdr->sh_link;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 		if (keylink == SHN_BEFORE)
3687c478bd9Sstevel@tonic-gate 			st->st_before[num_before++] = isp;
3697c478bd9Sstevel@tonic-gate 		else if (keylink == SHN_AFTER)
3707c478bd9Sstevel@tonic-gate 			st->st_after[num_after++] = isp;
3717c478bd9Sstevel@tonic-gate 		else
3727c478bd9Sstevel@tonic-gate 			st->st_order[num_order++] = isp;
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate 	return (1);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate static int
3787c478bd9Sstevel@tonic-gate comp(const void *ss1, const void *ss2)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	Is_desc		*s1 = *((Is_desc **)ss1);
3817c478bd9Sstevel@tonic-gate 	Is_desc		*s2 = *((Is_desc **)ss2);
3827c478bd9Sstevel@tonic-gate 	Is_desc		*i1, *i2;
3837c478bd9Sstevel@tonic-gate 	Word		ndx1, ndx2;
3847c478bd9Sstevel@tonic-gate 
385*0e233487SRod Evans 	if (s1->is_shdr->sh_flags & SHF_ORDERED)
3867c478bd9Sstevel@tonic-gate 		ndx1 = s1->is_shdr->sh_info;
387*0e233487SRod Evans 	else
3887c478bd9Sstevel@tonic-gate 		ndx1 = s1->is_shdr->sh_link;
3897c478bd9Sstevel@tonic-gate 
390*0e233487SRod Evans 	if (s2->is_shdr->sh_flags & SHF_ORDERED)
3917c478bd9Sstevel@tonic-gate 		ndx2 = s2->is_shdr->sh_info;
392*0e233487SRod Evans 	else
3937c478bd9Sstevel@tonic-gate 		ndx2 = s2->is_shdr->sh_link;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	i1 = s1->is_file->ifl_isdesc[ndx1];
3967c478bd9Sstevel@tonic-gate 	i2 = s2->is_file->ifl_isdesc[ndx2];
3977c478bd9Sstevel@tonic-gate 
398*0e233487SRod Evans 	if (i1->is_keyident > i2->is_keyident)
3997c478bd9Sstevel@tonic-gate 		return (1);
400*0e233487SRod Evans 	if (i1->is_keyident < i2->is_keyident)
4017c478bd9Sstevel@tonic-gate 		return (-1);
4027c478bd9Sstevel@tonic-gate 	return (0);
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate uintptr_t
4065aefb655Srie ld_sort_ordered(Ofl_desc *ofl)
4077c478bd9Sstevel@tonic-gate {
4087c478bd9Sstevel@tonic-gate 	Listnode *lnp1;
4097c478bd9Sstevel@tonic-gate 	Os_desc *osp;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	DBG_CALL(Dbg_sec_order_list(ofl, 0));
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	/*
4147c478bd9Sstevel@tonic-gate 	 * Sort Sections
4157c478bd9Sstevel@tonic-gate 	 */
4167c478bd9Sstevel@tonic-gate 	for (LIST_TRAVERSE(&ofl->ofl_ordered, lnp1, osp)) {
4177c478bd9Sstevel@tonic-gate 		int		i;
4187c478bd9Sstevel@tonic-gate 		List		islist;
4197c478bd9Sstevel@tonic-gate 		Listnode *	lnp2;
4207c478bd9Sstevel@tonic-gate 		Is_desc *	isp;
4217c478bd9Sstevel@tonic-gate 		Sort_desc *	st = osp->os_sort;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 		if (setup_sortbuf(osp) == 0)
4247c478bd9Sstevel@tonic-gate 			return (S_ERROR);
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 		islist = osp->os_isdescs;
4277c478bd9Sstevel@tonic-gate 		osp->os_isdescs.head = 0;
4287c478bd9Sstevel@tonic-gate 		osp->os_isdescs.tail = 0;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 		/*
4317c478bd9Sstevel@tonic-gate 		 * Sorting.
4327c478bd9Sstevel@tonic-gate 		 * First Sort the ordered sections.
4337c478bd9Sstevel@tonic-gate 		 */
4347c478bd9Sstevel@tonic-gate 		if (st->st_ordercnt != 0)
4357c478bd9Sstevel@tonic-gate 			qsort((char *)st->st_order, st->st_ordercnt,
4367c478bd9Sstevel@tonic-gate 			    sizeof (Is_desc *), comp);
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 		/*
4397c478bd9Sstevel@tonic-gate 		 * Place SHN_BEFORE at head of list
4407c478bd9Sstevel@tonic-gate 		 */
4417c478bd9Sstevel@tonic-gate 		for (i = 0; i < st->st_beforecnt; i++) {
442cce0e03bSab196087 			if (ld_append_isp(ofl, osp, st->st_before[i], 0) == 0)
4437c478bd9Sstevel@tonic-gate 				return (S_ERROR);
4447c478bd9Sstevel@tonic-gate 		}
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 		/*
4477c478bd9Sstevel@tonic-gate 		 * Next come 'linked' ordered sections
4487c478bd9Sstevel@tonic-gate 		 */
4497c478bd9Sstevel@tonic-gate 		for (i = 0; i < st->st_ordercnt; i++) {
450cce0e03bSab196087 			if (ld_append_isp(ofl, osp, st->st_order[i], 0) == 0)
4517c478bd9Sstevel@tonic-gate 				return (S_ERROR);
4527c478bd9Sstevel@tonic-gate 		}
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 		/*
4557c478bd9Sstevel@tonic-gate 		 * Now we list any sections which have no sorting
4567c478bd9Sstevel@tonic-gate 		 * specifications - in the order they were input.
457cce0e03bSab196087 		 *
458cce0e03bSab196087 		 * We use list_appendc() here instead of ld_append_isp(),
459cce0e03bSab196087 		 * because these items have already been inserted once, and
460cce0e03bSab196087 		 * we don't want any duplicate entries in osp->os_mstridescs.
4617c478bd9Sstevel@tonic-gate 		 */
4627c478bd9Sstevel@tonic-gate 		for (LIST_TRAVERSE(&islist, lnp2, isp)) {
4637c478bd9Sstevel@tonic-gate 			if (isp->is_flags & FLG_IS_ORDERED)
4647c478bd9Sstevel@tonic-gate 				continue;
4657c478bd9Sstevel@tonic-gate 			if (list_appendc(&(osp->os_isdescs),
4667c478bd9Sstevel@tonic-gate 			    isp) == 0)
4677c478bd9Sstevel@tonic-gate 				return (S_ERROR);
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 		/*
4717c478bd9Sstevel@tonic-gate 		 * And the end of the list are the SHN_AFTER sections.
4727c478bd9Sstevel@tonic-gate 		 */
4737c478bd9Sstevel@tonic-gate 		for (i = 0; i < st->st_aftercnt; i++) {
474cce0e03bSab196087 			if (ld_append_isp(ofl, osp, st->st_after[i], 0) == 0)
4757c478bd9Sstevel@tonic-gate 				return (S_ERROR);
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 	DBG_CALL(Dbg_sec_order_list(ofl, 1));
4797c478bd9Sstevel@tonic-gate 	return (0);
4807c478bd9Sstevel@tonic-gate }
481