xref: /illumos-gate/usr/src/cmd/sgs/libld/common/order.c (revision 6a634c9d)
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 /*
23*1007fd6fSAli Bahrami  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Processing of SHF_ORDERED sections.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate #include	<stdio.h>
307c478bd9Sstevel@tonic-gate #include	<fcntl.h>
317c478bd9Sstevel@tonic-gate #include	<link.h>
325aefb655Srie #include	<debug.h>
337c478bd9Sstevel@tonic-gate #include	"msg.h"
347c478bd9Sstevel@tonic-gate #include	"_libld.h"
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate /*
371dd9d86fSAli Bahrami  * Section Ordering History/Background:
381dd9d86fSAli Bahrami  *
391dd9d86fSAli Bahrami  * There are two forms of section ordering, SHF_ORDERED, and SHF_LINK_ORDER.
401dd9d86fSAli Bahrami  *
411dd9d86fSAli Bahrami  * SHF_ORDERED was invented at Sun in order to support the PowerPC port
421dd9d86fSAli Bahrami  * of Solaris 2.6, which used it for sorting tag words which describe
431dd9d86fSAli Bahrami  * the state of callee saves registers for given PC ranges. It was defined
441dd9d86fSAli Bahrami  * in the OS specific ELF section flag range. Some other values were defined
451dd9d86fSAli Bahrami  * at the same time:
461dd9d86fSAli Bahrami  *	SHF_EXCLUDE - Section is to be excluded from executables or shared
471dd9d86fSAli Bahrami  *		objects, and only kept in relocatable object output.
481dd9d86fSAli Bahrami  *	SHN_BEFORE/SHN_AFTER - Sections are placed before/after all other
491dd9d86fSAli Bahrami  *		sections, in the order they are encountered by the linker.
501dd9d86fSAli Bahrami  * Although initially conceived to support the PowerPC, the functionality
511dd9d86fSAli Bahrami  * was implemented for all platforms, and was later used to manage C++
521dd9d86fSAli Bahrami  * exceptions and stack unwinding. The PowerPC port was discontinued after
531dd9d86fSAli Bahrami  * one release, but SHF_ORDERED lives on.
541dd9d86fSAli Bahrami  *
551dd9d86fSAli Bahrami  * SHF_LINK_ORDER was invented later by the wider ELF community, and is
561dd9d86fSAli Bahrami  * therefore assigned a value in the generic ELF section flag range. It is
571dd9d86fSAli Bahrami  * essentially a simpler version of SHF_ORDERED, dispensing with some
581dd9d86fSAli Bahrami  * unnecessary features. The Solaris implementation of SHF_LINK_ORDER uses
591dd9d86fSAli Bahrami  * SHF_EXCLUDE, and SHF_BEFORE/SHN_AFTER as well, but it appears that these
601dd9d86fSAli Bahrami  * are still Solaris-only extensions not used by other implementations.
611dd9d86fSAli Bahrami  * SHF_LINK_ORDER has superseded SHF_ORDERED. The older mechanism is
621dd9d86fSAli Bahrami  * supported for the benefit of old pre-existing objects.
631dd9d86fSAli Bahrami  *
641dd9d86fSAli Bahrami  * -----
651dd9d86fSAli Bahrami  *
661dd9d86fSAli Bahrami  * SHF_ORDERED offers two distinct and separate abilities:
671dd9d86fSAli Bahrami  *
681dd9d86fSAli Bahrami  *	(1) To specify the output section
691dd9d86fSAli Bahrami  *	(2) To optionally be sorted relative to other sorted sections,
701dd9d86fSAli Bahrami  *		using a non-sorted section as a sort key.
711dd9d86fSAli Bahrami  *
721dd9d86fSAli Bahrami  * To  do this, it uses both the sh_link, and sh_info fields:
731dd9d86fSAli Bahrami  *
741dd9d86fSAli Bahrami  *    sh_link
751dd9d86fSAli Bahrami  *	Specifies the output section to receive this input section.
761dd9d86fSAli Bahrami  *	The sh_link field of an SHF_ORDERED section forms a linked list of
771dd9d86fSAli Bahrami  *	sections, all of which must have identical section header flags
781dd9d86fSAli Bahrami  *	(including SHF_ORDERED). The list is terminated by a final section
791dd9d86fSAli Bahrami  *	with a sh_link that points at itself. All input sections in this list
801dd9d86fSAli Bahrami  *	are assigned to the output section of the final section in the list.
811dd9d86fSAli Bahrami  *	Hence, if a section points at itself, the effect is that it gets
821dd9d86fSAli Bahrami  *	assigned to an output section in the usual default manner (i.e. an
831dd9d86fSAli Bahrami  *	output section with the same name as the input). However, it can
841dd9d86fSAli Bahrami  *	point at any arbitrary other section. This is a way to put a section
851dd9d86fSAli Bahrami  *	with one name into an output section with a different name. It should
861dd9d86fSAli Bahrami  *	be noted that this is of little value overall, because the link-editor
871dd9d86fSAli Bahrami  *	already supports a more general feature for directing input sections
881dd9d86fSAli Bahrami  *	to output sections: An input section named .text%foo will be sent to
891dd9d86fSAli Bahrami  *	an output section named ".text", and this works for all sections,
901dd9d86fSAli Bahrami  *	not just ordered ones.
911dd9d86fSAli Bahrami  *
921dd9d86fSAli Bahrami  *    sh_info
931dd9d86fSAli Bahrami  *	If sh_info is in the range (1 <= value < shnum), then this input section
941dd9d86fSAli Bahrami  *	is added to the group of sorted sections. The section referenced by
951dd9d86fSAli Bahrami  *	sh_info must be unsorted, and is used as the sort key.
961dd9d86fSAli Bahrami  *
971dd9d86fSAli Bahrami  *	If sh_info is SHN_BEFORE or SHN_AFTER, it is put in the pre/post group,
981dd9d86fSAli Bahrami  *	in the order it arrives (the before/after classes are not sorted).
991dd9d86fSAli Bahrami  *
1001dd9d86fSAli Bahrami  *	If sh_info is "invalid" (typically 0), then this section is added to
1011dd9d86fSAli Bahrami  *	the group of non-sorted sections, and goes into the output file in the
1021dd9d86fSAli Bahrami  *	order it arrives. This is not a valuable feature, as the same effect
1031dd9d86fSAli Bahrami  *	can be achieved more simply by not setting SHF_ORDERED at all.
1041dd9d86fSAli Bahrami  *
1051dd9d86fSAli Bahrami  * SHF_LINK_ORDER is a simplification of SHF_ORDERED. It uses sh_link to specify
1061dd9d86fSAli Bahrami  * the section to use as a sort key and sh_info is set to 0. The standard
1071dd9d86fSAli Bahrami  * ".text%foo" mechanism is used to direct input sections to output sections,
1081dd9d86fSAli Bahrami  * and unordered sections indicate that by not setting SHF_LINK_ORDER.
1097c478bd9Sstevel@tonic-gate  */
1101dd9d86fSAli Bahrami 
1111dd9d86fSAli Bahrami 
1127c478bd9Sstevel@tonic-gate /*
1131dd9d86fSAli Bahrami  * A "keyshndx" is the section index for the unordered section that should
1141dd9d86fSAli Bahrami  * be used as a sort key for a ordered section. Verify that the given
1151dd9d86fSAli Bahrami  * keyshndx is valid.
1161dd9d86fSAli Bahrami  *
1171dd9d86fSAli Bahrami  * exit:
1181dd9d86fSAli Bahrami  *	Returns 0 if the keyshndx is valid. A non-zero DBG_ORDER_ code is
1191dd9d86fSAli Bahrami  *	returned if the keyshndx is not valid to describe the problem.
1207c478bd9Sstevel@tonic-gate  */
121e23c41c9SAli Bahrami inline static Word
is_keyshndx_ok(Ifl_desc * ifl,Word keyshndx)1221dd9d86fSAli Bahrami is_keyshndx_ok(Ifl_desc *ifl, Word keyshndx)
1237c478bd9Sstevel@tonic-gate {
1241dd9d86fSAli Bahrami 	if ((keyshndx == SHN_BEFORE) || (keyshndx == SHN_AFTER))
125e23c41c9SAli Bahrami 		return (0);
126e23c41c9SAli Bahrami 
127e23c41c9SAli Bahrami 	/*
128e23c41c9SAli Bahrami 	 * Validate the key range.
129e23c41c9SAli Bahrami 	 */
1301dd9d86fSAli Bahrami 	if ((keyshndx == 0) || (keyshndx >= ifl->ifl_shnum))
131e23c41c9SAli Bahrami 		return (DBG_ORDER_LINK_OUTRANGE);
132e23c41c9SAli Bahrami 
133e23c41c9SAli Bahrami 	/*
1341dd9d86fSAli Bahrami 	 * The section pointed to by keyshndx should not be an ordered section.
1351dd9d86fSAli Bahrami 	 * Strictly speaking, we could test for SHF_ORDERED here instead of
1361dd9d86fSAli Bahrami 	 * ALL_SHF_ORDER as the two ordering flags are not supposed to be
1371dd9d86fSAli Bahrami 	 * mixed. Using ALL_SHF_ORDER costs the same and ensures that such
1381dd9d86fSAli Bahrami 	 * mixing doesn't go undetected.
139e23c41c9SAli Bahrami 	 */
1401dd9d86fSAli Bahrami 	if (ifl->ifl_isdesc[keyshndx]->is_shdr->sh_flags & ALL_SHF_ORDER)
141e23c41c9SAli Bahrami 		return (DBG_ORDER_INFO_ORDER);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	return (0);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate 
146e23c41c9SAli Bahrami /*
1471dd9d86fSAli Bahrami  * The sh_link field of an SHF_ORDERED section forms a linked list of
1481dd9d86fSAli Bahrami  * sections. The list is terminated by a final section with a sh_link
1491dd9d86fSAli Bahrami  * that points at itself. Given the index of an SHF_ORDERED section, find
1501dd9d86fSAli Bahrami  * the index of the final section in the list.
1511dd9d86fSAli Bahrami  *
1521dd9d86fSAli Bahrami  * entry:
1531dd9d86fSAli Bahrami  *	ofl - Output file descriptor
1541dd9d86fSAli Bahrami  *	ifl - Input file descriptor
1551dd9d86fSAli Bahrami  *	ndx - Section index of SHF_ORDERED section
1561dd9d86fSAli Bahrami  *	alt_os_name - Address of pointer to string. If the final section
1571dd9d86fSAli Bahrami  *		name is different than the section given by ndx, *alt_os_name
1581dd9d86fSAli Bahrami  *		will be updated with the name of the final section. The caller
1591dd9d86fSAli Bahrami  *		should initialize *alt_os_name to NULL before calling
1601dd9d86fSAli Bahrami  *		this routine.
1611dd9d86fSAli Bahrami  *
1621dd9d86fSAli Bahrami  * exit:
1631dd9d86fSAli Bahrami  *	On success: If the final section is different than the section
1641dd9d86fSAli Bahrami  *	given by ndx, then *alt_os_name is set to its name. TRUE is returned.
1651dd9d86fSAli Bahrami  *
1661dd9d86fSAli Bahrami  *	On failure, FALSE is returned.
167e23c41c9SAli Bahrami  */
1681dd9d86fSAli Bahrami static Boolean
validate_shf_ordered_dest(Ofl_desc * ofl,Ifl_desc * ifl,Word ndx,const char ** alt_os_name)1691dd9d86fSAli Bahrami validate_shf_ordered_dest(Ofl_desc *ofl, Ifl_desc *ifl, Word ndx,
1701dd9d86fSAli Bahrami     const char **alt_os_name)
1717c478bd9Sstevel@tonic-gate {
1721dd9d86fSAli Bahrami 	Word	shnum = ifl->ifl_shnum;
1731dd9d86fSAli Bahrami 	Word	isp1_ndx, isp2_ndx;
1741dd9d86fSAli Bahrami 	Is_desc	*isp1, *isp2;
17557ef7aa9SRod Evans 	int	error = 0;
1761dd9d86fSAli Bahrami 	size_t	iter = 0;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	/*
1791dd9d86fSAli Bahrami 	 * Traverse the list until we find the termination, or encounter
1801dd9d86fSAli Bahrami 	 * an invalid condition in the object that prevents ordering.
1817c478bd9Sstevel@tonic-gate 	 */
1821dd9d86fSAli Bahrami 	isp1_ndx = ndx;
1831dd9d86fSAli Bahrami 	isp1 = ifl->ifl_isdesc[ndx];
1847c478bd9Sstevel@tonic-gate 	do {
1857c478bd9Sstevel@tonic-gate 		/*
1861dd9d86fSAli Bahrami 		 * Obtain index of next section in list. Ensure it is in range.
1877c478bd9Sstevel@tonic-gate 		 */
1881dd9d86fSAli Bahrami 		isp2_ndx = isp1->is_shdr->sh_link;
1891dd9d86fSAli Bahrami 		if ((isp2_ndx == 0) || (isp2_ndx >= shnum)) {
1907c478bd9Sstevel@tonic-gate 			error = DBG_ORDER_LINK_OUTRANGE;
1917c478bd9Sstevel@tonic-gate 			break;
1927c478bd9Sstevel@tonic-gate 		}
1931dd9d86fSAli Bahrami 		isp2 = ifl->ifl_isdesc[isp2_ndx];
1947c478bd9Sstevel@tonic-gate 
1951dd9d86fSAli Bahrami 		/* The section flags must match exactly */
1967c478bd9Sstevel@tonic-gate 		if (isp1->is_shdr->sh_flags != isp2->is_shdr->sh_flags) {
1971dd9d86fSAli Bahrami 			/*
1981dd9d86fSAli Bahrami 			 * The case where the next section in the list does
1991dd9d86fSAli Bahrami 			 * not have the same ordered flag set as the original
2001dd9d86fSAli Bahrami 			 * ordered section gets a unique error code. This
2011dd9d86fSAli Bahrami 			 * provides more accurate/useful debugging diagnostics.
2021dd9d86fSAli Bahrami 			 */
2031dd9d86fSAli Bahrami 			error = ((isp2->is_flags & FLG_IS_ORDERED) == 0) ?
2041dd9d86fSAli Bahrami 			    DBG_ORDER_LINK_ERROR : DBG_ORDER_FLAGS;
2057c478bd9Sstevel@tonic-gate 			break;
2067c478bd9Sstevel@tonic-gate 		}
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 		/*
2091dd9d86fSAli Bahrami 		 * The sh_info field specifies the section index of an
2101dd9d86fSAli Bahrami 		 * unorderd section which will be used as a sort key.
2111dd9d86fSAli Bahrami 		 * Ensure it is in range. If not, we terminate the list
2121dd9d86fSAli Bahrami 		 * at the current node instead of continuing on.
2137c478bd9Sstevel@tonic-gate 		 */
2141dd9d86fSAli Bahrami 		if ((error = is_keyshndx_ok(ifl, isp2->is_shdr->sh_info)) != 0)
2157c478bd9Sstevel@tonic-gate 			break;
2167c478bd9Sstevel@tonic-gate 
2171dd9d86fSAli Bahrami 		/* If the section points at itself, it terminates the list */
2181dd9d86fSAli Bahrami 		if (isp1_ndx == isp2_ndx)
2197c478bd9Sstevel@tonic-gate 			break;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 		/*
2221dd9d86fSAli Bahrami 		 * Advance to next section in list
2237c478bd9Sstevel@tonic-gate 		 */
2241dd9d86fSAli Bahrami 		isp1_ndx = isp2_ndx;
2251dd9d86fSAli Bahrami 		isp1 = isp2;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 		/*
2281dd9d86fSAli Bahrami 		 * If we loop more times than the input file has sections,
2291dd9d86fSAli Bahrami 		 * we have encountered a malformed object in which the list
2301dd9d86fSAli Bahrami 		 * of SHF_ORDERED sections has a cycle. This can only happen
2311dd9d86fSAli Bahrami 		 * if the compiler generating the object has a bad bug.
2327c478bd9Sstevel@tonic-gate 		 */
2331dd9d86fSAli Bahrami 		if (++iter >= shnum) {
2347c478bd9Sstevel@tonic-gate 			error = DBG_ORDER_CYCLIC;
2357c478bd9Sstevel@tonic-gate 			break;
2367c478bd9Sstevel@tonic-gate 		}
2377c478bd9Sstevel@tonic-gate 	/* CONSTANTCONDITION */
2387c478bd9Sstevel@tonic-gate 	} while (1);
2397c478bd9Sstevel@tonic-gate 
2401dd9d86fSAli Bahrami 	/*
2411dd9d86fSAli Bahrami 	 * If we have found a problem, issue a debug diagnostic and map
2421dd9d86fSAli Bahrami 	 * the output section to 0. This indicates that the section should
2431dd9d86fSAli Bahrami 	 * remove the ordering flag and treat it as a standard section.
2441dd9d86fSAli Bahrami 	 */
2457c478bd9Sstevel@tonic-gate 	if (error != 0) {
2461dd9d86fSAli Bahrami 		isp2_ndx = 0;
2475aefb655Srie 		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
2487c478bd9Sstevel@tonic-gate 	}
2491dd9d86fSAli Bahrami 
2501dd9d86fSAli Bahrami 	/* Report success */
2511dd9d86fSAli Bahrami 	if (isp2_ndx != 0) {
2521dd9d86fSAli Bahrami 		/*
2531dd9d86fSAli Bahrami 		 * If the destination section is different than the input
2541dd9d86fSAli Bahrami 		 * section, then set *alt_os_name to the destination name.
2551dd9d86fSAli Bahrami 		 */
2561dd9d86fSAli Bahrami 		if (isp2_ndx != ndx)
2571dd9d86fSAli Bahrami 			*alt_os_name = ifl->ifl_isdesc[isp2_ndx]->is_name;
2581dd9d86fSAli Bahrami 		return (TRUE);
2591dd9d86fSAli Bahrami 	}
2601dd9d86fSAli Bahrami 
2611dd9d86fSAli Bahrami 	/* If we get here, there is no valid destination */
2621dd9d86fSAli Bahrami 	return (FALSE);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate /*
2661dd9d86fSAli Bahrami  * Called when an ordered section has a problem that prevents ordering.
2671dd9d86fSAli Bahrami  * The order flag is removed, and then the section is placed as an
2681dd9d86fSAli Bahrami  * unsorted section.
2691dd9d86fSAli Bahrami  */
2701dd9d86fSAli Bahrami static uintptr_t
place_unordered(Ofl_desc * ofl,Is_desc * isp,Place_path_info * path_info)27169112eddSAli Bahrami place_unordered(Ofl_desc *ofl, Is_desc *isp, Place_path_info *path_info)
2721dd9d86fSAli Bahrami {
2731dd9d86fSAli Bahrami 	isp->is_flags &= ~FLG_IS_ORDERED;
2741dd9d86fSAli Bahrami 	if (isp->is_osdesc == NULL)
27569112eddSAli Bahrami 		return ((uintptr_t)ld_place_section(ofl, isp, path_info,
2761dd9d86fSAli Bahrami 		    isp->is_keyident, NULL));
2771dd9d86fSAli Bahrami 	return ((uintptr_t)isp->is_osdesc);
2781dd9d86fSAli Bahrami }
2791dd9d86fSAli Bahrami 
2801dd9d86fSAli Bahrami /*
2811dd9d86fSAli Bahrami  * Process ordered input section. Called from process_elf() after
2821dd9d86fSAli Bahrami  * all the non-ordered sections have been placed.
2831dd9d86fSAli Bahrami  *
2841dd9d86fSAli Bahrami  * entry:
2851dd9d86fSAli Bahrami  *	ofl - Output file descriptor
2861dd9d86fSAli Bahrami  *	ifl - Input file descriptor
2871dd9d86fSAli Bahrami  *	ndx - Section index of SHF_ORDERED section
2881dd9d86fSAli Bahrami  *
2891dd9d86fSAli Bahrami  * exit:
2907c478bd9Sstevel@tonic-gate  */
2917c478bd9Sstevel@tonic-gate uintptr_t
ld_process_ordered(Ofl_desc * ofl,Ifl_desc * ifl,Place_path_info * path_info,Word ndx)29269112eddSAli Bahrami ld_process_ordered(Ofl_desc *ofl, Ifl_desc *ifl, Place_path_info *path_info,
29369112eddSAli Bahrami     Word ndx)
2947c478bd9Sstevel@tonic-gate {
29557ef7aa9SRod Evans 	Is_desc		*isp2, *isp = ifl->ifl_isdesc[ndx];
2967c478bd9Sstevel@tonic-gate 	Xword		shflags = isp->is_shdr->sh_flags;
2971dd9d86fSAli Bahrami 	const char	*alt_os_name = NULL;
2981dd9d86fSAli Bahrami 	Word		keyshndx;
2991dd9d86fSAli Bahrami 	Os_desc		*osp;
3007c478bd9Sstevel@tonic-gate 	int		error = 0;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	/*
3031dd9d86fSAli Bahrami 	 * Obtain the sort key section index for this ordered section.
3041dd9d86fSAli Bahrami 	 * SHF_ORDERED uses sh_info, while SHF_LINK_ORDER uses sh_link.
3051dd9d86fSAli Bahrami 	 * In order for this function to be called, one of SHF_ORDERED
3061dd9d86fSAli Bahrami 	 * or SHF_LINK_ORDER must be set. Testing for one implies the
3071dd9d86fSAli Bahrami 	 * state of the other.
3087c478bd9Sstevel@tonic-gate 	 */
3091dd9d86fSAli Bahrami 	keyshndx = (shflags & SHF_ORDERED) ?
3101dd9d86fSAli Bahrami 	    isp->is_shdr->sh_info : isp->is_shdr->sh_link;
3117c478bd9Sstevel@tonic-gate 
3121dd9d86fSAli Bahrami 	/*
3131dd9d86fSAli Bahrami 	 * Validate the sort key section index. If something is wrong,
3141dd9d86fSAli Bahrami 	 * fall back to treating it as a non-ordered section.
3151dd9d86fSAli Bahrami 	 */
3161dd9d86fSAli Bahrami 	if ((error = is_keyshndx_ok(ifl, keyshndx)) != 0) {
3175aefb655Srie 		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
31869112eddSAli Bahrami 		return (place_unordered(ofl, isp, path_info));
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/*
3221dd9d86fSAli Bahrami 	 * If SHF_ORDERED is in effect, validate the destination section
3231dd9d86fSAli Bahrami 	 * name given by sh_link, and set alt_os_name to the name of the
3241dd9d86fSAli Bahrami 	 * destination if it differs from the section being processed.
3257c478bd9Sstevel@tonic-gate 	 */
3261dd9d86fSAli Bahrami 	if ((shflags & SHF_ORDERED) &&
3271dd9d86fSAli Bahrami 	    (validate_shf_ordered_dest(ofl, ifl, ndx, &alt_os_name) == FALSE))
32869112eddSAli Bahrami 		return (place_unordered(ofl, isp, path_info));
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	/*
331e23c41c9SAli Bahrami 	 * Place the section into its output section. It's possible that this
332e23c41c9SAli Bahrami 	 * section is discarded (possibly because it's defined COMDAT), in
333e23c41c9SAli Bahrami 	 * which case we're done.
3347c478bd9Sstevel@tonic-gate 	 */
3357c478bd9Sstevel@tonic-gate 	if ((osp = isp->is_osdesc) == NULL) {
33669112eddSAli Bahrami 		osp = ld_place_section(ofl, isp, path_info, isp->is_keyident,
33769112eddSAli Bahrami 		    alt_os_name);
3381dd9d86fSAli Bahrami 		if ((osp == (Os_desc *)S_ERROR) || (osp == NULL))
3391dd9d86fSAli Bahrami 			return ((uintptr_t)osp);
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/*
34357ef7aa9SRod Evans 	 * If the output section is not yet on the ordered list, place it on
34457ef7aa9SRod Evans 	 * the list.
3457c478bd9Sstevel@tonic-gate 	 */
3461dd9d86fSAli Bahrami 	if (aplist_test(&ofl->ofl_ordered, osp, AL_CNT_OFL_ORDERED) ==
3471dd9d86fSAli Bahrami 	    ALE_ALLOCFAIL)
34857ef7aa9SRod Evans 		return ((uintptr_t)S_ERROR);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	/*
3511dd9d86fSAli Bahrami 	 * Output section has been found - set up its sorting information.
3527c478bd9Sstevel@tonic-gate 	 */
3531dd9d86fSAli Bahrami 	if ((keyshndx != SHN_BEFORE) && (keyshndx != SHN_AFTER)) {
3541dd9d86fSAli Bahrami 		Os_desc		*osp2;
3551dd9d86fSAli Bahrami 
3561dd9d86fSAli Bahrami 		isp2 = ifl->ifl_isdesc[keyshndx];
3577c478bd9Sstevel@tonic-gate 		if (isp2->is_flags & FLG_IS_DISCARD) {
358*1007fd6fSAli Bahrami 			ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_BADORDREF),
359*1007fd6fSAli Bahrami 			    ifl->ifl_name, EC_WORD(isp->is_scnndx),
360*1007fd6fSAli Bahrami 			    isp->is_name, EC_WORD(isp2->is_scnndx),
361*1007fd6fSAli Bahrami 			    isp2->is_name);
3627c478bd9Sstevel@tonic-gate 			return (S_ERROR);
3637c478bd9Sstevel@tonic-gate 		}
3640e233487SRod Evans 
3650e233487SRod Evans 		/*
3661dd9d86fSAli Bahrami 		 * Indicate that this ordered input section will require a
3671dd9d86fSAli Bahrami 		 * sort key.  Propagate the key requirement through to the
3681dd9d86fSAli Bahrami 		 * associated output section, segment and file, to trigger
3691dd9d86fSAli Bahrami 		 * the sort key creation.  See ld_sec_validate();
3700e233487SRod Evans 		 */
3710e233487SRod Evans 		isp2->is_flags |= FLG_IS_KEY;
3720e233487SRod Evans 
3737c478bd9Sstevel@tonic-gate 		osp2 = isp2->is_osdesc;
3740e233487SRod Evans 		osp2->os_flags |= FLG_OS_KEY;
3757c478bd9Sstevel@tonic-gate 		osp2->os_sgdesc->sg_flags |= FLG_SG_KEY;
3760e233487SRod Evans 
3770e233487SRod Evans 		ofl->ofl_flags |= FLG_OF_KEY;
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	return ((uintptr_t)osp);
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate  * Traverse all segments looking for section ordering information that hasn't
3857c478bd9Sstevel@tonic-gate  * been used.  If found give a warning message to the user.  Also, check if
3861dd9d86fSAli Bahrami  * there are any ordered key sections, and if so set up sort key values.
3877c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate void
ld_sec_validate(Ofl_desc * ofl)3890bc07c75Srie ld_sec_validate(Ofl_desc *ofl)
3907c478bd9Sstevel@tonic-gate {
39157ef7aa9SRod Evans 	Aliste		idx1;
3920bc07c75Srie 	Sg_desc		*sgp;
3930e233487SRod Evans 	Word 		key = 1;
3947c478bd9Sstevel@tonic-gate 
39557ef7aa9SRod Evans 	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
396cce0e03bSab 		Sec_order	*scop;
397cce0e03bSab 		Os_desc		*osp;
39857ef7aa9SRod Evans 		Aliste		idx2;
3997c478bd9Sstevel@tonic-gate 
40069112eddSAli Bahrami 		for (ALIST_TRAVERSE(sgp->sg_os_order, idx2, scop)) {
4010bc07c75Srie 			if ((scop->sco_flags & FLG_SGO_USED) == 0) {
402*1007fd6fSAli Bahrami 				ld_eprintf(ofl, ERR_WARNING,
4035aefb655Srie 				    MSG_INTL(MSG_MAP_SECORDER),
4047c478bd9Sstevel@tonic-gate 				    sgp->sg_name, scop->sco_secname);
4050bc07c75Srie 			}
4060bc07c75Srie 		}
4077c478bd9Sstevel@tonic-gate 		if ((sgp->sg_flags & FLG_SG_KEY) == 0)
4087c478bd9Sstevel@tonic-gate 			continue;
4097c478bd9Sstevel@tonic-gate 
41057ef7aa9SRod Evans 		for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
41157ef7aa9SRod Evans 			Aliste	idx3;
41257ef7aa9SRod Evans 			Is_desc	*isp;
4137c478bd9Sstevel@tonic-gate 
4140e233487SRod Evans 			if ((osp->os_flags & FLG_OS_KEY) == 0)
4157c478bd9Sstevel@tonic-gate 				continue;
4167c478bd9Sstevel@tonic-gate 
4171dd9d86fSAli Bahrami 			/*
4181dd9d86fSAli Bahrami 			 * The input sections used as sort keys are required
4191dd9d86fSAli Bahrami 			 * to be unordered, so we only have to look at the
4201dd9d86fSAli Bahrami 			 * DEFAULT list of input sections.
4211dd9d86fSAli Bahrami 			 */
4221dd9d86fSAli Bahrami 			for (APLIST_TRAVERSE(osp->os_isdescs[OS_ISD_DEFAULT],
4231dd9d86fSAli Bahrami 			    idx3, isp)) {
4240bc07c75Srie 				if (isp->is_flags & FLG_IS_KEY)
4250e233487SRod Evans 					isp->is_keyident = key++;
4267c478bd9Sstevel@tonic-gate 			}
4277c478bd9Sstevel@tonic-gate 		}
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate static int
comp(const void * ss1,const void * ss2)4327c478bd9Sstevel@tonic-gate comp(const void *ss1, const void *ss2)
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate 	Is_desc		*s1 = *((Is_desc **)ss1);
4357c478bd9Sstevel@tonic-gate 	Is_desc		*s2 = *((Is_desc **)ss2);
4367c478bd9Sstevel@tonic-gate 	Is_desc		*i1, *i2;
4377c478bd9Sstevel@tonic-gate 	Word		ndx1, ndx2;
4387c478bd9Sstevel@tonic-gate 
4390e233487SRod Evans 	if (s1->is_shdr->sh_flags & SHF_ORDERED)
4407c478bd9Sstevel@tonic-gate 		ndx1 = s1->is_shdr->sh_info;
4410e233487SRod Evans 	else
4427c478bd9Sstevel@tonic-gate 		ndx1 = s1->is_shdr->sh_link;
4437c478bd9Sstevel@tonic-gate 
4440e233487SRod Evans 	if (s2->is_shdr->sh_flags & SHF_ORDERED)
4457c478bd9Sstevel@tonic-gate 		ndx2 = s2->is_shdr->sh_info;
4460e233487SRod Evans 	else
4477c478bd9Sstevel@tonic-gate 		ndx2 = s2->is_shdr->sh_link;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	i1 = s1->is_file->ifl_isdesc[ndx1];
4507c478bd9Sstevel@tonic-gate 	i2 = s2->is_file->ifl_isdesc[ndx2];
4517c478bd9Sstevel@tonic-gate 
4520e233487SRod Evans 	if (i1->is_keyident > i2->is_keyident)
4537c478bd9Sstevel@tonic-gate 		return (1);
4540e233487SRod Evans 	if (i1->is_keyident < i2->is_keyident)
4557c478bd9Sstevel@tonic-gate 		return (-1);
4567c478bd9Sstevel@tonic-gate 	return (0);
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate 
4591dd9d86fSAli Bahrami /*
4601dd9d86fSAli Bahrami  * Sort ordered input sections
4611dd9d86fSAli Bahrami  */
4627c478bd9Sstevel@tonic-gate uintptr_t
ld_sort_ordered(Ofl_desc * ofl)4635aefb655Srie ld_sort_ordered(Ofl_desc *ofl)
4647c478bd9Sstevel@tonic-gate {
46557ef7aa9SRod Evans 	Aliste	idx1;
4667c478bd9Sstevel@tonic-gate 	Os_desc *osp;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	DBG_CALL(Dbg_sec_order_list(ofl, 0));
4697c478bd9Sstevel@tonic-gate 
47057ef7aa9SRod Evans 	for (APLIST_TRAVERSE(ofl->ofl_ordered, idx1, osp)) {
4711dd9d86fSAli Bahrami 		APlist	*ap_list = osp->os_isdescs[OS_ISD_ORDERED];
4721dd9d86fSAli Bahrami 		Aliste	apl_nitems = aplist_nitems(ap_list);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 		/*
4751dd9d86fSAli Bahrami 		 * If this output section has a non-empty list of ordered
4761dd9d86fSAli Bahrami 		 * input sections, sort their APlist in place into their
4771dd9d86fSAli Bahrami 		 * final order.
4787c478bd9Sstevel@tonic-gate 		 */
4791dd9d86fSAli Bahrami 		if (apl_nitems != 0)
4801dd9d86fSAli Bahrami 			qsort((char *)ap_list->apl_data, apl_nitems,
481cce0e03bSab 			    sizeof (Is_desc *), comp);
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 	DBG_CALL(Dbg_sec_order_list(ofl, 1));
4847c478bd9Sstevel@tonic-gate 	return (0);
4857c478bd9Sstevel@tonic-gate }
486