xref: /titanic_51/usr/src/cmd/sgs/libld/common/libs.c (revision 875546ac7519c97db0e3ce165c9b9d5147e27c8d)
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 /*
237c478bd9Sstevel@tonic-gate  *	Copyright (c) 1988 AT&T
247c478bd9Sstevel@tonic-gate  *	  All Rights Reserved
257c478bd9Sstevel@tonic-gate  *
26dc0f59e5SAli Bahrami  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Library processing
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate #include	<stdio.h>
337c478bd9Sstevel@tonic-gate #include	<string.h>
34*875546acSRichard Lowe #include	<errno.h>
35dc0f59e5SAli Bahrami #include	<ar.h>
365aefb655Srie #include	<debug.h>
377c478bd9Sstevel@tonic-gate #include	"msg.h"
387c478bd9Sstevel@tonic-gate #include	"_libld.h"
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
418dea2860Srie  * Archive members are typically extracted to resolve an existing undefined
428dea2860Srie  * reference.  However, other symbol definitions can cause archive members to
438dea2860Srie  * be processed to determine if the archive member provides a more appropriate
448dea2860Srie  * definition.  This routine processes the archive member to determine if the
458dea2860Srie  * member is really required.
468dea2860Srie  *
478dea2860Srie  *  i.	Tentative symbols may cause the extraction of an archive member.
488dea2860Srie  *	If the archive member has a strong defined symbol it will be used.
498dea2860Srie  *	If the archive member simply contains another tentative definition,
508dea2860Srie  *	or a defined function symbol, then it will not be used.
518dea2860Srie  *
528dea2860Srie  *  ii.	A symbol reference may define a hidden or protected visibility.  The
538dea2860Srie  *	reference can only be bound to a definition within a relocatable object
548dea2860Srie  *	for this restricted visibility to be satisfied.  If the archive member
558dea2860Srie  * 	provides a definition of the same symbol type, this definition is
568dea2860Srie  *	taken.  The visibility of the defined symbol is irrelevant, as the most
578dea2860Srie  *	restrictive visibility of the reference and the definition will be
588dea2860Srie  *	applied to the final symbol.
59dc0f59e5SAli Bahrami  *
60dc0f59e5SAli Bahrami  * exit:
61dc0f59e5SAli Bahrami  *	Returns 1 if there is a match, 0 if no match is seen, and S_ERROR if an
62dc0f59e5SAli Bahrami  *	error occurred.
637c478bd9Sstevel@tonic-gate  */
64dc0f59e5SAli Bahrami static uintptr_t
658dea2860Srie process_member(Ar_mem *amp, const char *name, Sym_desc *sdp, Ofl_desc *ofl)
667c478bd9Sstevel@tonic-gate {
678dea2860Srie 	Sym	*syms, *osym = sdp->sd_sym;
687c478bd9Sstevel@tonic-gate 	Xword	symn, cnt;
697c478bd9Sstevel@tonic-gate 	char 	*strs;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	/*
727c478bd9Sstevel@tonic-gate 	 * Find the first symbol table in the archive member, obtain its
737c478bd9Sstevel@tonic-gate 	 * data buffer and determine the number of global symbols (Note,
747c478bd9Sstevel@tonic-gate 	 * there must be a symbol table present otherwise the archive would
757c478bd9Sstevel@tonic-gate 	 * never have been able to generate its own symbol entry for this
767c478bd9Sstevel@tonic-gate 	 * member).
777c478bd9Sstevel@tonic-gate 	 */
7857ef7aa9SRod Evans 	if (amp->am_syms == NULL) {
797c478bd9Sstevel@tonic-gate 		Elf_Scn		*scn = NULL;
807c478bd9Sstevel@tonic-gate 		Shdr		*shdr;
817c478bd9Sstevel@tonic-gate 		Elf_Data	*data;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 		while (scn = elf_nextscn(amp->am_elf, scn)) {
847c478bd9Sstevel@tonic-gate 			if ((shdr = elf_getshdr(scn)) == NULL) {
851007fd6fSAli Bahrami 				ld_eprintf(ofl, ERR_ELF,
865aefb655Srie 				    MSG_INTL(MSG_ELF_GETSHDR), amp->am_path);
87dc0f59e5SAli Bahrami 				return (S_ERROR);
887c478bd9Sstevel@tonic-gate 			}
897c478bd9Sstevel@tonic-gate 			if ((shdr->sh_type == SHT_SYMTAB) ||
907c478bd9Sstevel@tonic-gate 			    (shdr->sh_type == SHT_DYNSYM))
917c478bd9Sstevel@tonic-gate 				break;
927c478bd9Sstevel@tonic-gate 		}
937c478bd9Sstevel@tonic-gate 		if ((data = elf_getdata(scn, NULL)) == NULL) {
941007fd6fSAli Bahrami 			ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETDATA),
951007fd6fSAli Bahrami 			    amp->am_path);
96dc0f59e5SAli Bahrami 			return (S_ERROR);
977c478bd9Sstevel@tonic-gate 		}
987c478bd9Sstevel@tonic-gate 		syms = (Sym *)data->d_buf;
997c478bd9Sstevel@tonic-gate 		syms += shdr->sh_info;
1007c478bd9Sstevel@tonic-gate 		symn = shdr->sh_size / shdr->sh_entsize;
1017c478bd9Sstevel@tonic-gate 		symn -= shdr->sh_info;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 		/*
1047c478bd9Sstevel@tonic-gate 		 * Get the data for the associated string table.
1057c478bd9Sstevel@tonic-gate 		 */
1067c478bd9Sstevel@tonic-gate 		if ((scn = elf_getscn(amp->am_elf, (size_t)shdr->sh_link)) ==
1077c478bd9Sstevel@tonic-gate 		    NULL) {
1081007fd6fSAli Bahrami 			ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETSCN),
1091007fd6fSAli Bahrami 			    amp->am_path);
110dc0f59e5SAli Bahrami 			return (S_ERROR);
1117c478bd9Sstevel@tonic-gate 		}
1127c478bd9Sstevel@tonic-gate 		if ((data = elf_getdata(scn, NULL)) == NULL) {
1131007fd6fSAli Bahrami 			ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETDATA),
1141007fd6fSAli Bahrami 			    amp->am_path);
115dc0f59e5SAli Bahrami 			return (S_ERROR);
1167c478bd9Sstevel@tonic-gate 		}
1177c478bd9Sstevel@tonic-gate 		strs = data->d_buf;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 		/*
1207c478bd9Sstevel@tonic-gate 		 * Initialize the archive member structure in case we have to
1217c478bd9Sstevel@tonic-gate 		 * come through here again.
1227c478bd9Sstevel@tonic-gate 		 */
1237c478bd9Sstevel@tonic-gate 		amp->am_syms = syms;
1247c478bd9Sstevel@tonic-gate 		amp->am_strs = strs;
1257c478bd9Sstevel@tonic-gate 		amp->am_symn = symn;
1267c478bd9Sstevel@tonic-gate 	} else {
1277c478bd9Sstevel@tonic-gate 		syms = amp->am_syms;
1287c478bd9Sstevel@tonic-gate 		strs = amp->am_strs;
1297c478bd9Sstevel@tonic-gate 		symn = amp->am_symn;
1307c478bd9Sstevel@tonic-gate 	}
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	/*
1337c478bd9Sstevel@tonic-gate 	 * Loop through the symbol table entries looking for a match for the
1348dea2860Srie 	 * original symbol.
1357c478bd9Sstevel@tonic-gate 	 */
1367c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < symn; syms++, cnt++) {
1378dea2860Srie 		Word	shndx;
1387c478bd9Sstevel@tonic-gate 
1398dea2860Srie 		if ((shndx = syms->st_shndx) == SHN_UNDEF)
1408dea2860Srie 			continue;
1418dea2860Srie 
1428dea2860Srie 		if (osym->st_shndx == SHN_COMMON) {
1438dea2860Srie 			/*
1448dea2860Srie 			 * Determine whether a tentative symbol definition
1458dea2860Srie 			 * should be overridden.
1468dea2860Srie 			 */
1477c478bd9Sstevel@tonic-gate 			if ((shndx == SHN_ABS) || (shndx == SHN_COMMON) ||
1488dea2860Srie 			    (ELF_ST_TYPE(syms->st_info) == STT_FUNC))
1497c478bd9Sstevel@tonic-gate 				continue;
1507c478bd9Sstevel@tonic-gate 
1518dea2860Srie 			/*
1528dea2860Srie 			 * A historic detail requires that a weak definition
1538dea2860Srie 			 * within an archive will not override a strong
1548dea2860Srie 			 * definition (see sym_realtent() resolution and ABI
1558dea2860Srie 			 * symbol binding description - page 4-27).
1568dea2860Srie 			 */
1578dea2860Srie 			if ((ELF_ST_BIND(syms->st_info) == STB_WEAK) &&
1588dea2860Srie 			    (ELF_ST_BIND(osym->st_info) != STB_WEAK))
1597c478bd9Sstevel@tonic-gate 				continue;
1608dea2860Srie 		} else {
1618dea2860Srie 			/*
1628dea2860Srie 			 * Determine whether a restricted visibility reference
1638dea2860Srie 			 * should be overridden.  Don't worry about the
1648dea2860Srie 			 * visibility of the archive member definition, nor
1658dea2860Srie 			 * whether it is weak or global.  Any definition is
1668dea2860Srie 			 * better than a binding to an external shared object
1678dea2860Srie 			 * (which is the only event that must presently exist
1688dea2860Srie 			 * for us to be here looking for a better alternative).
1698dea2860Srie 			 */
1708dea2860Srie 			if (ELF_ST_TYPE(syms->st_info) !=
1718dea2860Srie 			    ELF_ST_TYPE(osym->st_info))
1728dea2860Srie 				continue;
1738dea2860Srie 		}
1747c478bd9Sstevel@tonic-gate 
1756b3ba5bdSAli Bahrami 		if (strcmp(strs + syms->st_name, name) == 0)
1767c478bd9Sstevel@tonic-gate 			return (1);
1777c478bd9Sstevel@tonic-gate 	}
1787c478bd9Sstevel@tonic-gate 	return (0);
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * Create an archive descriptor.  By maintaining a list of archives any
1837c478bd9Sstevel@tonic-gate  * duplicate occurrences of the same archive specified by the user enable us to
1847c478bd9Sstevel@tonic-gate  * pick off where the last processing finished.
1857c478bd9Sstevel@tonic-gate  */
1867c478bd9Sstevel@tonic-gate Ar_desc *
1875aefb655Srie ld_ar_setup(const char *name, Elf *elf, Ofl_desc *ofl)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate 	Ar_desc *	adp;
1907c478bd9Sstevel@tonic-gate 	size_t		number;
1917c478bd9Sstevel@tonic-gate 	Elf_Arsym *	start;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	/*
194dc0f59e5SAli Bahrami 	 * Unless, -z allextract is specified, get the archive symbol table
195dc0f59e5SAli Bahrami 	 * if one exists, and ignore the file with a warning message otherwise.
1967c478bd9Sstevel@tonic-gate 	 */
197dc0f59e5SAli Bahrami 	if (ofl->ofl_flags1 & FLG_OF1_ALLEXRT) {
198dc0f59e5SAli Bahrami 		start = NULL;
199dc0f59e5SAli Bahrami 	} else  if ((start = elf_getarsym(elf, &number)) == NULL) {
2001007fd6fSAli Bahrami 		if (elf_errno())
2011007fd6fSAli Bahrami 			ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETARSYM),
2021007fd6fSAli Bahrami 			    name);
2031007fd6fSAli Bahrami 		else
2041007fd6fSAli Bahrami 			ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_ELF_ARSYM),
2051007fd6fSAli Bahrami 			    name);
2067c478bd9Sstevel@tonic-gate 		return (0);
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	/*
2107c478bd9Sstevel@tonic-gate 	 * As this is a new archive reference establish a new descriptor.
2117c478bd9Sstevel@tonic-gate 	 */
21257ef7aa9SRod Evans 	if ((adp = libld_malloc(sizeof (Ar_desc))) == NULL)
2137c478bd9Sstevel@tonic-gate 		return ((Ar_desc *)S_ERROR);
2147c478bd9Sstevel@tonic-gate 	adp->ad_name = name;
2157c478bd9Sstevel@tonic-gate 	adp->ad_elf = elf;
2167c478bd9Sstevel@tonic-gate 	adp->ad_start = start;
217dc0f59e5SAli Bahrami 	if (start) {
218dc0f59e5SAli Bahrami 		adp->ad_aux = libld_calloc(sizeof (Ar_aux), number);
219dc0f59e5SAli Bahrami 		if (adp->ad_aux == NULL)
2207c478bd9Sstevel@tonic-gate 			return ((Ar_desc *)S_ERROR);
221dc0f59e5SAli Bahrami 	} else {
222dc0f59e5SAli Bahrami 		adp->ad_aux = NULL;
223dc0f59e5SAli Bahrami 	}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	/*
2267c478bd9Sstevel@tonic-gate 	 * Retain any command line options that are applicable to archive
2277c478bd9Sstevel@tonic-gate 	 * extraction in case we have to rescan this archive later.
2287c478bd9Sstevel@tonic-gate 	 */
2297c478bd9Sstevel@tonic-gate 	adp->ad_flags = ofl->ofl_flags1 & MSK_OF1_ARCHIVE;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	ofl->ofl_arscnt++;
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	/*
2347c478bd9Sstevel@tonic-gate 	 * Add this new descriptor to the list of archives.
2357c478bd9Sstevel@tonic-gate 	 */
23657ef7aa9SRod Evans 	if (aplist_append(&ofl->ofl_ars, adp, AL_CNT_OFL_LIBS) == NULL)
2377c478bd9Sstevel@tonic-gate 		return ((Ar_desc *)S_ERROR);
2387c478bd9Sstevel@tonic-gate 	else
2397c478bd9Sstevel@tonic-gate 		return (adp);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate /*
2435aefb655Srie  * For each archive descriptor, maintain an `Ar_aux' table to parallel the
2445aefb655Srie  * archive symbol table (returned from elf_getarsym(3e)).  Use this table to
2455aefb655Srie  * hold a `Sym_desc' for each symbol (thus reducing the number of
2465aefb655Srie  * ld_sym_find()'s), and to hold the `Ar_mem' pointer.  The `Ar_mem' element
2475aefb655Srie  * can have one of three values indicating the state of the archive member
2487c478bd9Sstevel@tonic-gate  * associated with the offset for this symbol table entry:
2497c478bd9Sstevel@tonic-gate  *
2507c478bd9Sstevel@tonic-gate  *  0		indicates that the member has not been processed.
2517c478bd9Sstevel@tonic-gate  *
2527c478bd9Sstevel@tonic-gate  *  FLG_ARMEM_PROC
2537c478bd9Sstevel@tonic-gate  *		indicates that the member has been processed.
2547c478bd9Sstevel@tonic-gate  *
2557c478bd9Sstevel@tonic-gate  *  addr	indicates that the member has been investigated to determine if
2567c478bd9Sstevel@tonic-gate  *		it contained a symbol definition we need, but was found not to
2577c478bd9Sstevel@tonic-gate  *		be a candidate for extraction.  In this case the members
2587c478bd9Sstevel@tonic-gate  *		structure is maintained for possible later use.
2597c478bd9Sstevel@tonic-gate  *
2607c478bd9Sstevel@tonic-gate  * Each time we process an archive member we use its offset value to scan this
2617c478bd9Sstevel@tonic-gate  * `Ar_aux' list.  If the member has been extracted, each entry with the same
262a6d4d7d5SRod Evans  * offset has its `Ar_mem' pointer set to FLG_ARMEM_PROC.  Thus if we cycle back
2637c478bd9Sstevel@tonic-gate  * through the archive symbol table we will ignore these symbols as they will
2647c478bd9Sstevel@tonic-gate  * have already been added to the output image.  If a member has been processed
2657c478bd9Sstevel@tonic-gate  * but found not to contain a symbol we need, each entry with the same offset
2667c478bd9Sstevel@tonic-gate  * has its `Ar_mem' pointer set to the member structures address.
2677c478bd9Sstevel@tonic-gate  */
2687c478bd9Sstevel@tonic-gate void
2695aefb655Srie ld_ar_member(Ar_desc * adp, Elf_Arsym * arsym, Ar_aux * aup, Ar_mem * amp)
2707c478bd9Sstevel@tonic-gate {
2717c478bd9Sstevel@tonic-gate 	Elf_Arsym *	_arsym = arsym;
2727c478bd9Sstevel@tonic-gate 	Ar_aux *	_aup = aup;
2737c478bd9Sstevel@tonic-gate 	size_t		_off = arsym->as_off;
2747c478bd9Sstevel@tonic-gate 
275dc0f59e5SAli Bahrami 	if (adp->ad_start == NULL)
276dc0f59e5SAli Bahrami 		return;
277dc0f59e5SAli Bahrami 
278dc0f59e5SAli Bahrami 	/*
279dc0f59e5SAli Bahrami 	 * Note: This algorithm assumes that the archive symbol table is
280dc0f59e5SAli Bahrami 	 * built from the member objects, in the same order as those
281dc0f59e5SAli Bahrami 	 * members are found in the archive. As such, the symbols for a
282dc0f59e5SAli Bahrami 	 * given member will all cluster together. If this is not true,
283dc0f59e5SAli Bahrami 	 * we will fail to mark some symbols. In that case, archive
284dc0f59e5SAli Bahrami 	 * processing may be less efficient than it would be otherwise.
285dc0f59e5SAli Bahrami 	 */
286dc0f59e5SAli Bahrami 
2877c478bd9Sstevel@tonic-gate 	if (_arsym != adp->ad_start) {
2887c478bd9Sstevel@tonic-gate 		do {
2897c478bd9Sstevel@tonic-gate 			_arsym--;
2907c478bd9Sstevel@tonic-gate 			_aup--;
2917c478bd9Sstevel@tonic-gate 			if (_arsym->as_off != _off)
2927c478bd9Sstevel@tonic-gate 				break;
2937c478bd9Sstevel@tonic-gate 			_aup->au_mem = amp;
2947c478bd9Sstevel@tonic-gate 		} while (_arsym != adp->ad_start);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	_arsym = arsym;
2987c478bd9Sstevel@tonic-gate 	_aup = aup;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	do {
3017c478bd9Sstevel@tonic-gate 		if (_arsym->as_off != _off)
3027c478bd9Sstevel@tonic-gate 			break;
3037c478bd9Sstevel@tonic-gate 		_aup->au_mem = amp;
3047c478bd9Sstevel@tonic-gate 		_arsym++;
3057c478bd9Sstevel@tonic-gate 		_aup++;
3067c478bd9Sstevel@tonic-gate 	} while (_arsym->as_name);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /*
3102a93c375SAli Bahrami  * Return the archive member's name.
311dc0f59e5SAli Bahrami  *
312dc0f59e5SAli Bahrami  * entry:
313dc0f59e5SAli Bahrami  *	name - Name of archive
3142a93c375SAli Bahrami  *	arelf - ELF descriptor for archive member.
315dc0f59e5SAli Bahrami  *	ofl - output descriptor
316dc0f59e5SAli Bahrami  *
317dc0f59e5SAli Bahrami  * exit:
3182a93c375SAli Bahrami  *	Returns pointer to archive member name on success, NULL on error.
319dc0f59e5SAli Bahrami  */
3202a93c375SAli Bahrami static const char *
3212a93c375SAli Bahrami ar_member_name(const char *name, Elf *arelf, Ofl_desc *ofl)
322dc0f59e5SAli Bahrami {
323dc0f59e5SAli Bahrami 	Elf_Arhdr	*arhdr;
324dc0f59e5SAli Bahrami 
3252a93c375SAli Bahrami 	if ((arhdr = elf_getarhdr(arelf)) == NULL) {
3261007fd6fSAli Bahrami 		ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETARHDR), name);
3272a93c375SAli Bahrami 		return (NULL);
328dc0f59e5SAli Bahrami 	}
3292a93c375SAli Bahrami 	return (arhdr->ar_name);
330dc0f59e5SAli Bahrami }
331dc0f59e5SAli Bahrami 
332dc0f59e5SAli Bahrami /*
3332a93c375SAli Bahrami  * Construct the member's full pathname, using the format "%s(%s)".
3342a93c375SAli Bahrami  *
3352a93c375SAli Bahrami  * entry:
3362a93c375SAli Bahrami  *	name - Name of archive
3372a93c375SAli Bahrami  *	arname - Name of archive member
338*875546acSRichard Lowe  *	ofl - output descriptor
3392a93c375SAli Bahrami  * exit:
3402a93c375SAli Bahrami  *	Returns pointer to constructed pathname on success, NULL on error.
341dc0f59e5SAli Bahrami  */
3422a93c375SAli Bahrami static const char *
343*875546acSRichard Lowe ar_member_path(const char *name, const char *arname, Ofl_desc *ofl)
3442a93c375SAli Bahrami {
3452a93c375SAli Bahrami 	size_t		len;
3462a93c375SAli Bahrami 	char		*path;
347dc0f59e5SAli Bahrami 
3482a93c375SAli Bahrami 	len = strlen(name) + strlen(arname) + 3;
349*875546acSRichard Lowe 	if ((path = libld_malloc(len)) == NULL) {
350*875546acSRichard Lowe 		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_MALLOC),
351*875546acSRichard Lowe 		    strerror(errno));
3522a93c375SAli Bahrami 		return (NULL);
353*875546acSRichard Lowe 	}
3542a93c375SAli Bahrami 	(void) snprintf(path, len, MSG_ORIG(MSG_FMT_ARMEM), name, arname);
3552a93c375SAli Bahrami 	return (path);
356dc0f59e5SAli Bahrami }
357dc0f59e5SAli Bahrami 
358dc0f59e5SAli Bahrami /*
359dc0f59e5SAli Bahrami  * Input the specified archive member to the link.
360dc0f59e5SAli Bahrami  *
361dc0f59e5SAli Bahrami  * entry:
362dc0f59e5SAli Bahrami  *	fd - Open file descriptor for archive
363dc0f59e5SAli Bahrami  *	adp - Archive descriptor
364dc0f59e5SAli Bahrami  *	ofl - output descriptor
365dc0f59e5SAli Bahrami  *	arelf - ELF descriptor for archive member.
366dc0f59e5SAli Bahrami  *	arpath - Address of pointer to be set to constructed path name
367dc0f59e5SAli Bahrami  *		for object.
368dc0f59e5SAli Bahrami  *	rej - Rejection descriptor to pass to ld_process_ifl().
369dc0f59e5SAli Bahrami  *
370dc0f59e5SAli Bahrami  * exit:
371dc0f59e5SAli Bahrami  *	This routine can return one of the following:
372dc0f59e5SAli Bahrami  *	S_ERROR:  Fatal error encountered.
373dc0f59e5SAli Bahrami  *	0: Object was rejected, and should be ignored.
374dc0f59e5SAli Bahrami  *		rej will carry the rejection information.
375dc0f59e5SAli Bahrami  *	1: The archive member has been input to the link.
376dc0f59e5SAli Bahrami  */
377dc0f59e5SAli Bahrami static uintptr_t
3782a93c375SAli Bahrami ar_input(int fd, Ar_desc *adp, Ofl_desc *ofl, Elf *arelf,
379dc0f59e5SAli Bahrami     const char *arpath, Rej_desc *rej)
380dc0f59e5SAli Bahrami {
381dc0f59e5SAli Bahrami 	Rej_desc	_rej = { 0 };
382dc0f59e5SAli Bahrami 
383dc0f59e5SAli Bahrami 	switch (ld_process_ifl(arpath, NULL, fd, arelf,
384dc0f59e5SAli Bahrami 	    (FLG_IF_EXTRACT | FLG_IF_NEEDED), ofl, &_rej, NULL)) {
385dc0f59e5SAli Bahrami 	case S_ERROR:
386dc0f59e5SAli Bahrami 		return (S_ERROR);
387dc0f59e5SAli Bahrami 	case 0:
388dc0f59e5SAli Bahrami 		/*
389dc0f59e5SAli Bahrami 		 * If this member is rejected maintain the first rejection
390dc0f59e5SAli Bahrami 		 * error for possible later display.
391dc0f59e5SAli Bahrami 		 */
392dc0f59e5SAli Bahrami 		if (_rej.rej_type) {
393dc0f59e5SAli Bahrami 			if (rej->rej_type == 0) {
394dc0f59e5SAli Bahrami 				rej->rej_type = _rej.rej_type;
395dc0f59e5SAli Bahrami 				rej->rej_info = _rej.rej_info;
396dc0f59e5SAli Bahrami 				rej->rej_name = arpath;
397dc0f59e5SAli Bahrami 			}
398dc0f59e5SAli Bahrami 			(void) elf_end(arelf);
399dc0f59e5SAli Bahrami 			return (0);
400dc0f59e5SAli Bahrami 		}
401dc0f59e5SAli Bahrami 	}
402dc0f59e5SAli Bahrami 
403dc0f59e5SAli Bahrami 	/*
404dc0f59e5SAli Bahrami 	 * Indicate that the extracted member is in use.  This
405dc0f59e5SAli Bahrami 	 * enables debugging diags, and indicates that a further
406dc0f59e5SAli Bahrami 	 * rescan of all archives may be necessary.
407dc0f59e5SAli Bahrami 	 */
408dc0f59e5SAli Bahrami 	ofl->ofl_flags1 |= FLG_OF1_EXTRACT;
409dc0f59e5SAli Bahrami 	adp->ad_flags |= FLG_ARD_EXTRACT;
410dc0f59e5SAli Bahrami 	return (1);
411dc0f59e5SAli Bahrami }
412dc0f59e5SAli Bahrami 
413dc0f59e5SAli Bahrami /*
41460758829Srie  * Data structure to indicate whether a symbol is visible for the purpose
41560758829Srie  * of archive extraction.
41660758829Srie  */
41760758829Srie static const Boolean
41860758829Srie sym_vis[STV_NUM] = {
41960758829Srie 	TRUE,		/* STV_DEFAULT */
42060758829Srie 	FALSE,		/* STV_INTERNAL */
42160758829Srie 	FALSE,		/* STV_HIDDEN */
42260758829Srie 	FALSE,		/* STV_PROTECTED */
42360758829Srie 	TRUE,		/* STV_EXPORTED */
42460758829Srie 	TRUE,		/* STV_SINGLETON */
42560758829Srie 	FALSE		/* STV_ELIMINATE */
42660758829Srie };
42760758829Srie #if STV_NUM != (STV_ELIMINATE + 1)
42860758829Srie #error "STV_NUM has grown. Update sym_vis[]."
42960758829Srie #endif
43060758829Srie 
43160758829Srie /*
4328dea2860Srie  * Read the archive symbol table.  For each symbol in the table, determine
4338dea2860Srie  * whether that symbol satisfies an unresolved reference, tentative reference,
4348dea2860Srie  * or a reference that expects hidden or protected visibility.  If so, the
4358dea2860Srie  * corresponding object from the archive is processed.  The archive symbol
4368dea2860Srie  * table is searched until we go through a complete pass without satisfying any
4378dea2860Srie  * unresolved symbols
438dc0f59e5SAli Bahrami  *
439dc0f59e5SAli Bahrami  * entry:
440dc0f59e5SAli Bahrami  *	name - Name of archive
441dc0f59e5SAli Bahrami  *	fd - Open file descriptor for archive
442dc0f59e5SAli Bahrami  *	adp - Archive descriptor
443dc0f59e5SAli Bahrami  *	ofl - output descriptor
444dc0f59e5SAli Bahrami  *	found - Address of variable to set to TRUE if any objects are extracted
445dc0f59e5SAli Bahrami  *	rej - Rejection descriptor to pass to ld_process_ifl().
446dc0f59e5SAli Bahrami  *
447dc0f59e5SAli Bahrami  * exit:
448dc0f59e5SAli Bahrami  *	Returns FALSE on fatal error. On success, *found will be TRUE
449dc0f59e5SAli Bahrami  *	if any object was extracted, rej will be set if any object
450dc0f59e5SAli Bahrami  *	was rejected, and TRUE is returned.
4517c478bd9Sstevel@tonic-gate  */
452dc0f59e5SAli Bahrami static Boolean
4532a93c375SAli Bahrami ar_extract_bysym(const char *name, int fd, Ar_desc *adp,
454dc0f59e5SAli Bahrami     Ofl_desc *ofl, Boolean *found, Rej_desc *rej)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	Elf_Arsym *	arsym;
4577c478bd9Sstevel@tonic-gate 	Elf *		arelf;
4587c478bd9Sstevel@tonic-gate 	Ar_aux *	aup;
4597c478bd9Sstevel@tonic-gate 	Sym_desc *	sdp;
460dc0f59e5SAli Bahrami 	const char	*arname, *arpath;
461dc0f59e5SAli Bahrami 	Boolean		again = FALSE;
4627c478bd9Sstevel@tonic-gate 	uintptr_t	err;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	/*
465dc0f59e5SAli Bahrami 	 * An archive without a symbol table should not reach this function,
466dc0f59e5SAli Bahrami 	 * because it can only get past ld_ar_setup() in the case where
467dc0f59e5SAli Bahrami 	 * the archive is first seen under the influence of '-z allextract'.
468dc0f59e5SAli Bahrami 	 * That will cause the entire archive to be extracted, and any
469dc0f59e5SAli Bahrami 	 * subsequent reference to the archive will be ignored by
470dc0f59e5SAli Bahrami 	 * ld_process_archive().
4717c478bd9Sstevel@tonic-gate 	 */
472dc0f59e5SAli Bahrami 	if (adp->ad_start == NULL) {
473dc0f59e5SAli Bahrami 		assert(adp->ad_start != NULL);
474dc0f59e5SAli Bahrami 		return (TRUE);
475dc0f59e5SAli Bahrami 	}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	/*
4787c478bd9Sstevel@tonic-gate 	 * Loop through archive symbol table until we make a complete pass
4797c478bd9Sstevel@tonic-gate 	 * without satisfying an unresolved reference.  For each archive
4807c478bd9Sstevel@tonic-gate 	 * symbol, see if there is a symbol with the same name in ld's
4817c478bd9Sstevel@tonic-gate 	 * symbol table.  If so, and if that symbol is still unresolved or
4827c478bd9Sstevel@tonic-gate 	 * tentative, process the corresponding archive member.
4837c478bd9Sstevel@tonic-gate 	 */
4847c478bd9Sstevel@tonic-gate 	do {
4855aefb655Srie 		DBG_CALL(Dbg_file_ar(ofl->ofl_lml, name, again));
4865aefb655Srie 		DBG_CALL(Dbg_syms_ar_title(ofl->ofl_lml, name, again));
487dc0f59e5SAli Bahrami 		again = FALSE;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 		for (arsym = adp->ad_start, aup = adp->ad_aux; arsym->as_name;
490dc0f59e5SAli Bahrami 		    ++arsym, ++aup) {
4917c478bd9Sstevel@tonic-gate 			Ar_mem		*amp;
4927c478bd9Sstevel@tonic-gate 			Sym		*sym;
49360758829Srie 			Boolean		visible = TRUE;
494dc0f59e5SAli Bahrami 			Boolean		vers;
495dc0f59e5SAli Bahrami 			Ifl_desc	*ifl;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 			/*
4987c478bd9Sstevel@tonic-gate 			 * If the auxiliary members value indicates that this
4997c478bd9Sstevel@tonic-gate 			 * member has been processed then this symbol will have
5007c478bd9Sstevel@tonic-gate 			 * been added to the output file image already or the
5017c478bd9Sstevel@tonic-gate 			 * object was rejected in which case we don't want to
5027c478bd9Sstevel@tonic-gate 			 * process it again.
5037c478bd9Sstevel@tonic-gate 			 */
5047c478bd9Sstevel@tonic-gate 			if (aup->au_mem == FLG_ARMEM_PROC)
5057c478bd9Sstevel@tonic-gate 				continue;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 			/*
5087c478bd9Sstevel@tonic-gate 			 * If the auxiliary symbol element is non-zero lookup
5097c478bd9Sstevel@tonic-gate 			 * the symbol from the internal symbol table.
5107c478bd9Sstevel@tonic-gate 			 */
511dc0f59e5SAli Bahrami 			if ((sdp = aup->au_syms) == NULL) {
5125aefb655Srie 				if ((sdp = ld_sym_find(arsym->as_name,
5137c478bd9Sstevel@tonic-gate 				    /* LINTED */
514635216b6SRod Evans 				    (Word)arsym->as_hash, NULL, ofl)) == NULL) {
515dc0f59e5SAli Bahrami 					DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml,
516dc0f59e5SAli Bahrami 					    name, arsym));
5177c478bd9Sstevel@tonic-gate 					continue;
5187c478bd9Sstevel@tonic-gate 				}
5197c478bd9Sstevel@tonic-gate 				aup->au_syms = sdp;
5207c478bd9Sstevel@tonic-gate 			}
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 			/*
5237c478bd9Sstevel@tonic-gate 			 * With '-z allextract', all members will be extracted.
5247c478bd9Sstevel@tonic-gate 			 *
5257c478bd9Sstevel@tonic-gate 			 * This archive member is a candidate for extraction if
5268dea2860Srie 			 * the internal symbol originates from an explicit file,
5278dea2860Srie 			 * and represents an undefined or tentative symbol.
5288dea2860Srie 			 *
5298dea2860Srie 			 * By default, weak references do not cause archive
5308dea2860Srie 			 * extraction, however the -zweakextract flag overrides
5318dea2860Srie 			 * this default.
5328dea2860Srie 			 *
5338dea2860Srie 			 * If this symbol has already been bound to a versioned
5348dea2860Srie 			 * shared object, but the shared objects version is not
5358dea2860Srie 			 * available, then a definition of this symbol from
5368dea2860Srie 			 * within the archive is a better candidate.  Similarly,
5378dea2860Srie 			 * if this symbol has been bound to a shared object, but
5388dea2860Srie 			 * the original reference expected hidden or protected
5398dea2860Srie 			 * visibility, then a definition of this symbol from
5408dea2860Srie 			 * within the archive is a better candidate.
5417c478bd9Sstevel@tonic-gate 			 */
542dc0f59e5SAli Bahrami 			vers = TRUE;
543dc0f59e5SAli Bahrami 			ifl = sdp->sd_file;
5447c478bd9Sstevel@tonic-gate 
5458dea2860Srie 			sym = sdp->sd_sym;
5468dea2860Srie 
5478dea2860Srie 			if (sdp->sd_ref == REF_DYN_NEED) {
54860758829Srie 				uchar_t	vis;
5498dea2860Srie 
5508dea2860Srie 				if (ifl->ifl_vercnt) {
5517c478bd9Sstevel@tonic-gate 					Word		vndx;
5527c478bd9Sstevel@tonic-gate 					Ver_index	*vip;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 					vndx = sdp->sd_aux->sa_dverndx;
5558dea2860Srie 					vip = &ifl->ifl_verndx[vndx];
556dc0f59e5SAli Bahrami 					if (!(vip->vi_flags & FLG_VER_AVAIL))
5577c478bd9Sstevel@tonic-gate 						vers = FALSE;
5587c478bd9Sstevel@tonic-gate 				}
5597c478bd9Sstevel@tonic-gate 
56060758829Srie 				vis = ELF_ST_VISIBILITY(sym->st_other);
56160758829Srie 				visible = sym_vis[vis];
5628dea2860Srie 			}
5638dea2860Srie 
5648dea2860Srie 			if (((ifl->ifl_flags & FLG_IF_NEEDED) == 0) ||
565dc0f59e5SAli Bahrami 			    (visible && vers && (sym->st_shndx != SHN_UNDEF) &&
5668dea2860Srie 			    (sym->st_shndx != SHN_COMMON)) ||
5677c478bd9Sstevel@tonic-gate 			    ((ELF_ST_BIND(sym->st_info) == STB_WEAK) &&
5687c478bd9Sstevel@tonic-gate 			    (!(ofl->ofl_flags1 & FLG_OF1_WEAKEXT)))) {
569dc0f59e5SAli Bahrami 				DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml,
570dc0f59e5SAli Bahrami 				    name, arsym));
5717c478bd9Sstevel@tonic-gate 				continue;
5727c478bd9Sstevel@tonic-gate 			}
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 			/*
5757c478bd9Sstevel@tonic-gate 			 * Determine if we have already extracted this member,
5767c478bd9Sstevel@tonic-gate 			 * and if so reuse the Ar_mem information.
5777c478bd9Sstevel@tonic-gate 			 */
5787c478bd9Sstevel@tonic-gate 			if ((amp = aup->au_mem) != 0) {
5797c478bd9Sstevel@tonic-gate 				arelf = amp->am_elf;
5807c478bd9Sstevel@tonic-gate 				arname = amp->am_name;
5817c478bd9Sstevel@tonic-gate 				arpath = amp->am_path;
5827c478bd9Sstevel@tonic-gate 			} else {
5837c478bd9Sstevel@tonic-gate 				/*
5847c478bd9Sstevel@tonic-gate 				 * Set up a new elf descriptor for this member.
5857c478bd9Sstevel@tonic-gate 				 */
5867c478bd9Sstevel@tonic-gate 				if (elf_rand(adp->ad_elf, arsym->as_off) !=
5877c478bd9Sstevel@tonic-gate 				    arsym->as_off) {
5881007fd6fSAli Bahrami 					ld_eprintf(ofl, ERR_ELF,
5897c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_ELF_ARMEM), name,
590dc0f59e5SAli Bahrami 					    EC_WORD(arsym->as_off),
5917c478bd9Sstevel@tonic-gate 					    demangle(arsym->as_name));
592dc0f59e5SAli Bahrami 					return (FALSE);
5937c478bd9Sstevel@tonic-gate 				}
5943906e0c2Srie 
5957c478bd9Sstevel@tonic-gate 				if ((arelf = elf_begin(fd, ELF_C_READ,
5967c478bd9Sstevel@tonic-gate 				    adp->ad_elf)) == NULL) {
5971007fd6fSAli Bahrami 					ld_eprintf(ofl, ERR_ELF,
5987c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_ELF_BEGIN), name);
599dc0f59e5SAli Bahrami 					return (FALSE);
6007c478bd9Sstevel@tonic-gate 				}
6017c478bd9Sstevel@tonic-gate 
6022a93c375SAli Bahrami 				/* Get member filename */
6032a93c375SAli Bahrami 				if ((arname = ar_member_name(name, arelf,
6042a93c375SAli Bahrami 				    ofl)) == NULL)
605dc0f59e5SAli Bahrami 					return (FALSE);
6062a93c375SAli Bahrami 
6072a93c375SAli Bahrami 				/* Construct the member's full pathname */
608*875546acSRichard Lowe 				if ((arpath = ar_member_path(name, arname,
609*875546acSRichard Lowe 				    ofl)) == NULL)
610*875546acSRichard Lowe 					return (FALSE);
6112a93c375SAli Bahrami 
6122a93c375SAli Bahrami 				/*
6132a93c375SAli Bahrami 				 * Determine whether the support libraries wish
6142a93c375SAli Bahrami 				 * to process this open. See comments in
6152a93c375SAli Bahrami 				 * ld_process_open().
6162a93c375SAli Bahrami 				 */
6172a93c375SAli Bahrami 				ld_sup_open(ofl, &arpath, &arname, &fd,
6182a93c375SAli Bahrami 				    (FLG_IF_EXTRACT | FLG_IF_NEEDED),
6192a93c375SAli Bahrami 				    &arelf, adp->ad_elf, arsym->as_off,
6202a93c375SAli Bahrami 				    elf_kind(arelf));
6212a93c375SAli Bahrami 				if (arelf == NULL) {
6222a93c375SAli Bahrami 					/* Ignore this archive member */
623a6d4d7d5SRod Evans 					aup->au_mem = FLG_ARMEM_PROC;
624a6d4d7d5SRod Evans 					continue;
625a6d4d7d5SRod Evans 				}
6267c478bd9Sstevel@tonic-gate 			}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 			/*
6298dea2860Srie 			 * The symbol for which this archive member is being
6308dea2860Srie 			 * processed may provide a better alternative to the
6318dea2860Srie 			 * symbol that is presently known.  Two cases are
6328dea2860Srie 			 * covered:
6338dea2860Srie 			 *
6348dea2860Srie 			 *  i.	The present symbol represents tentative data.
6358dea2860Srie 			 *	The archive member may provide a data
6368dea2860Srie 			 *	definition symbol.
6378dea2860Srie 			 *  ii.	The present symbol represents a reference that
6388dea2860Srie 			 *	has seen a definition within a shared object
6398dea2860Srie 			 *	dependency, but the reference expects to be
6408dea2860Srie 			 *	reduced to hidden or protected visibility.
6417c478bd9Sstevel@tonic-gate 			 */
642dc0f59e5SAli Bahrami 			if ((sym->st_shndx == SHN_COMMON) ||
643dc0f59e5SAli Bahrami 			    (visible == FALSE)) {
6447c478bd9Sstevel@tonic-gate 				/*
6457c478bd9Sstevel@tonic-gate 				 * If we don't already have a member structure
6467c478bd9Sstevel@tonic-gate 				 * allocate one.
6477c478bd9Sstevel@tonic-gate 				 */
6487c478bd9Sstevel@tonic-gate 				if (!amp) {
6497c478bd9Sstevel@tonic-gate 					if ((amp = libld_calloc(sizeof (Ar_mem),
65057ef7aa9SRod Evans 					    1)) == NULL)
651dc0f59e5SAli Bahrami 						return (FALSE);
6527c478bd9Sstevel@tonic-gate 					amp->am_elf = arelf;
6537c478bd9Sstevel@tonic-gate 					amp->am_name = arname;
6547c478bd9Sstevel@tonic-gate 					amp->am_path = arpath;
6557c478bd9Sstevel@tonic-gate 				}
6565aefb655Srie 				DBG_CALL(Dbg_syms_ar_checking(ofl->ofl_lml,
657dc0f59e5SAli Bahrami 				    name, arname, arsym));
6587c478bd9Sstevel@tonic-gate 				if ((err = process_member(amp, arsym->as_name,
6598dea2860Srie 				    sdp, ofl)) == S_ERROR)
660dc0f59e5SAli Bahrami 					return (FALSE);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 				/*
6637c478bd9Sstevel@tonic-gate 				 * If it turns out that we don't need this
6647c478bd9Sstevel@tonic-gate 				 * member simply initialize all other auxiliary
6657c478bd9Sstevel@tonic-gate 				 * entries that match this offset with this
6667c478bd9Sstevel@tonic-gate 				 * members address.  In this way we can resuse
6677c478bd9Sstevel@tonic-gate 				 * this information if we recurse back to this
6687c478bd9Sstevel@tonic-gate 				 * symbol.
6697c478bd9Sstevel@tonic-gate 				 */
6707c478bd9Sstevel@tonic-gate 				if (err == 0) {
67157ef7aa9SRod Evans 					if (aup->au_mem == NULL)
6725aefb655Srie 						ld_ar_member(adp, arsym,
6735aefb655Srie 						    aup, amp);
6747c478bd9Sstevel@tonic-gate 					continue;
6757c478bd9Sstevel@tonic-gate 				}
6767c478bd9Sstevel@tonic-gate 			}
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 			/*
6797c478bd9Sstevel@tonic-gate 			 * Process the archive member.  Retain any error for
6807c478bd9Sstevel@tonic-gate 			 * return to the caller.
6817c478bd9Sstevel@tonic-gate 			 */
682dc0f59e5SAli Bahrami 			DBG_CALL(Dbg_syms_ar_resolve(ofl->ofl_lml,
683dc0f59e5SAli Bahrami 			    name, arname, arsym));
6842a93c375SAli Bahrami 			switch (ar_input(fd, adp, ofl, arelf, arpath,
685dc0f59e5SAli Bahrami 			    rej)) {
686dc0f59e5SAli Bahrami 			case S_ERROR:
687dc0f59e5SAli Bahrami 				return (FALSE);
688dc0f59e5SAli Bahrami 			case 0:
6897c478bd9Sstevel@tonic-gate 				/*
690dc0f59e5SAli Bahrami 				 * Mark the member as extracted so that we
691dc0f59e5SAli Bahrami 				 * don't try and process it again on a rescan.
6927c478bd9Sstevel@tonic-gate 				 */
6935aefb655Srie 				ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC);
6947c478bd9Sstevel@tonic-gate 				continue;
6957c478bd9Sstevel@tonic-gate 			}
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 			/*
698dc0f59e5SAli Bahrami 			 * Note that this archive has contributed something
699dc0f59e5SAli Bahrami 			 * during this specific operation, and also signal
700dc0f59e5SAli Bahrami 			 * the need to rescan the archive.
7017c478bd9Sstevel@tonic-gate 			 */
702dc0f59e5SAli Bahrami 			*found = again = TRUE;
7037c478bd9Sstevel@tonic-gate 
7045aefb655Srie 			ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC);
7057c478bd9Sstevel@tonic-gate 		}
7067c478bd9Sstevel@tonic-gate 	} while (again);
7077c478bd9Sstevel@tonic-gate 
708dc0f59e5SAli Bahrami 	return (TRUE);
709dc0f59e5SAli Bahrami }
710dc0f59e5SAli Bahrami 
711dc0f59e5SAli Bahrami 
712dc0f59e5SAli Bahrami /*
713dc0f59e5SAli Bahrami  * Extract every object in the given archive directly without going through
714dc0f59e5SAli Bahrami  * the symbol table.
715dc0f59e5SAli Bahrami  *
716dc0f59e5SAli Bahrami  * entry:
717dc0f59e5SAli Bahrami  *	name - Name of archive
718dc0f59e5SAli Bahrami  *	fd - Open file descriptor for archive
719dc0f59e5SAli Bahrami  *	adp - Archive descriptor
720dc0f59e5SAli Bahrami  *	ofl - output descriptor
721dc0f59e5SAli Bahrami  *	found - Address of variable to set to TRUE if any objects are extracted
722dc0f59e5SAli Bahrami  *	rej - Rejection descriptor to pass to ld_process_ifl().
723dc0f59e5SAli Bahrami  *
724dc0f59e5SAli Bahrami  * exit:
725dc0f59e5SAli Bahrami  *	Returns FALSE on fatal error. On success, *found will be TRUE
726dc0f59e5SAli Bahrami  *	if any object was extracted, rej will be set if any object
727dc0f59e5SAli Bahrami  *	was rejected, and TRUE is returned.
728dc0f59e5SAli Bahrami  */
729dc0f59e5SAli Bahrami static Boolean
7302a93c375SAli Bahrami ar_extract_all(const char *name, int fd, Ar_desc *adp, Ofl_desc *ofl,
731dc0f59e5SAli Bahrami     Boolean *found, Rej_desc *rej)
732dc0f59e5SAli Bahrami {
733dc0f59e5SAli Bahrami 	Elf_Cmd		cmd = ELF_C_READ;
734dc0f59e5SAli Bahrami 	Elf		*arelf;
735dc0f59e5SAli Bahrami 	const char	*arname, *arpath;
7362a93c375SAli Bahrami 	size_t		off, next_off;
737dc0f59e5SAli Bahrami 
738dc0f59e5SAli Bahrami 	DBG_CALL(Dbg_file_ar(ofl->ofl_lml, name, FALSE));
739dc0f59e5SAli Bahrami 
740dc0f59e5SAli Bahrami 	while ((arelf = elf_begin(fd, cmd, adp->ad_elf)) != NULL) {
741dc0f59e5SAli Bahrami 		/*
742dc0f59e5SAli Bahrami 		 * Call elf_next() so that the next call to elf_begin() will
743dc0f59e5SAli Bahrami 		 * fetch the archive member following this one. We do this now
744dc0f59e5SAli Bahrami 		 * because it simplifies the logic below, and because the
7452a93c375SAli Bahrami 		 * support libraries called below can set our handle to NULL.
746dc0f59e5SAli Bahrami 		 */
747dc0f59e5SAli Bahrami 		cmd = elf_next(arelf);
748dc0f59e5SAli Bahrami 
7492a93c375SAli Bahrami 		/* Get member filename */
7502a93c375SAli Bahrami 		if ((arname = ar_member_name(name, arelf, ofl)) == NULL)
751dc0f59e5SAli Bahrami 			return (FALSE);
7522a93c375SAli Bahrami 
7532a93c375SAli Bahrami 		/*
7542a93c375SAli Bahrami 		 * Skip the symbol table, string table, or any other special
7552a93c375SAli Bahrami 		 * archive member. These all start with a '/' character.
7562a93c375SAli Bahrami 		 */
7572a93c375SAli Bahrami 		if (*arname == '/') {
7582a93c375SAli Bahrami 			(void) elf_end(arelf);
759dc0f59e5SAli Bahrami 			continue;
760dc0f59e5SAli Bahrami 		}
761dc0f59e5SAli Bahrami 
7622a93c375SAli Bahrami 		/* Obtain archive member offset within the file */
7632a93c375SAli Bahrami 		off = _elf_getarhdrbase(arelf);
7642a93c375SAli Bahrami 
7652a93c375SAli Bahrami 		/*
7662a93c375SAli Bahrami 		 * ld_sup_open() will reset the current iteration point for
7672a93c375SAli Bahrami 		 * the archive to point at this member rather than the next
7682a93c375SAli Bahrami 		 * one for the benefit of the support libraries. Since
7692a93c375SAli Bahrami 		 * this loop relies on the current position not changing
7702a93c375SAli Bahrami 		 * underneath it, we save and restore the current
7712a93c375SAli Bahrami 		 * position around the support library call.
7722a93c375SAli Bahrami 		 */
7732a93c375SAli Bahrami 		next_off = _elf_getnextoff(adp->ad_elf);
7742a93c375SAli Bahrami 
7752a93c375SAli Bahrami 		/* Construct the member's full pathname */
776*875546acSRichard Lowe 		if ((arpath = ar_member_path(name, arname, ofl)) == NULL)
777*875546acSRichard Lowe 			return (FALSE);
7782a93c375SAli Bahrami 
7792a93c375SAli Bahrami 		/*
7802a93c375SAli Bahrami 		 * Determine whether the support libraries wish to process
7812a93c375SAli Bahrami 		 * this open. See comments in ld_process_open().
7822a93c375SAli Bahrami 		 */
7832a93c375SAli Bahrami 		ld_sup_open(ofl, &arpath, &arname, &fd,
7842a93c375SAli Bahrami 		    (FLG_IF_EXTRACT | FLG_IF_NEEDED), &arelf, adp->ad_elf,
7852a93c375SAli Bahrami 		    off, elf_kind(arelf));
7862a93c375SAli Bahrami 		(void) elf_rand(adp->ad_elf, next_off);
7872a93c375SAli Bahrami 		if (arelf == NULL)
7882a93c375SAli Bahrami 			continue;
7892a93c375SAli Bahrami 
790dc0f59e5SAli Bahrami 		DBG_CALL(Dbg_syms_ar_force(ofl->ofl_lml, name, arname));
7912a93c375SAli Bahrami 		switch (ar_input(fd, adp, ofl, arelf, arpath, rej)) {
792dc0f59e5SAli Bahrami 		case S_ERROR:
793dc0f59e5SAli Bahrami 			return (FALSE);
794dc0f59e5SAli Bahrami 		case 0:
795dc0f59e5SAli Bahrami 			continue;
796dc0f59e5SAli Bahrami 		}
797dc0f59e5SAli Bahrami 
798dc0f59e5SAli Bahrami 		*found = TRUE;
799dc0f59e5SAli Bahrami 
800dc0f59e5SAli Bahrami 	}
801dc0f59e5SAli Bahrami 
802dc0f59e5SAli Bahrami 	/*
803dc0f59e5SAli Bahrami 	 * As this archive was extracted by -z allextract, the ar_aux table
804dc0f59e5SAli Bahrami 	 * and elf descriptor can be freed.  Set ad_elf to NULL to mark the
805dc0f59e5SAli Bahrami 	 * archive is completely processed.
806dc0f59e5SAli Bahrami 	 */
807dc0f59e5SAli Bahrami 	(void) elf_end(adp->ad_elf);
808dc0f59e5SAli Bahrami 	adp->ad_elf = NULL;
809dc0f59e5SAli Bahrami 
810dc0f59e5SAli Bahrami 	return (TRUE);
811dc0f59e5SAli Bahrami }
812dc0f59e5SAli Bahrami 
813dc0f59e5SAli Bahrami 
814dc0f59e5SAli Bahrami /*
815dc0f59e5SAli Bahrami  * Process the given archive and extract objects for inclusion into
816dc0f59e5SAli Bahrami  * the link.
817dc0f59e5SAli Bahrami  *
818dc0f59e5SAli Bahrami  * entry:
819dc0f59e5SAli Bahrami  *	name - Name of archive
820dc0f59e5SAli Bahrami  *	fd - Open file descriptor for archive
821dc0f59e5SAli Bahrami  *	adp - Archive descriptor
822dc0f59e5SAli Bahrami  *	ofl - output descriptor
823dc0f59e5SAli Bahrami  *
824dc0f59e5SAli Bahrami  * exit:
825dc0f59e5SAli Bahrami  *	Returns FALSE on fatal error, TRUE otherwise.
826dc0f59e5SAli Bahrami  */
827dc0f59e5SAli Bahrami Boolean
828dc0f59e5SAli Bahrami ld_process_archive(const char *name, int fd, Ar_desc *adp, Ofl_desc *ofl)
829dc0f59e5SAli Bahrami {
830dc0f59e5SAli Bahrami 	Boolean		found = FALSE;
831dc0f59e5SAli Bahrami 	Rej_desc	rej = { 0 };
832dc0f59e5SAli Bahrami 
833dc0f59e5SAli Bahrami 	/*
834dc0f59e5SAli Bahrami 	 * If a fatal error condition has been set there's really no point in
835dc0f59e5SAli Bahrami 	 * processing the archive further.  Having got to this point we have at
836dc0f59e5SAli Bahrami 	 * least established that the archive exists (thus verifying that the
837dc0f59e5SAli Bahrami 	 * command line options that got us to this archive are correct).  Very
838dc0f59e5SAli Bahrami 	 * large archives can take a significant time to process, therefore
839dc0f59e5SAli Bahrami 	 * continuing on from here may significantly delay the fatal error
840dc0f59e5SAli Bahrami 	 * message the user is already set to receive.
841dc0f59e5SAli Bahrami 	 */
842dc0f59e5SAli Bahrami 	if (ofl->ofl_flags & FLG_OF_FATAL)
843dc0f59e5SAli Bahrami 		return (TRUE);
844dc0f59e5SAli Bahrami 
845dc0f59e5SAli Bahrami 	/*
846dc0f59e5SAli Bahrami 	 * If this archive was processed with -z allextract, then all members
847dc0f59e5SAli Bahrami 	 * have already been extracted.
848dc0f59e5SAli Bahrami 	 */
849dc0f59e5SAli Bahrami 	if (adp->ad_elf == NULL)
850dc0f59e5SAli Bahrami 		return (TRUE);
851dc0f59e5SAli Bahrami 
852dc0f59e5SAli Bahrami 	if (ofl->ofl_flags1 & FLG_OF1_ALLEXRT) {
8532a93c375SAli Bahrami 		if (!ar_extract_all(name, fd, adp, ofl, &found, &rej))
854dc0f59e5SAli Bahrami 			return (FALSE);
855dc0f59e5SAli Bahrami 	} else {
8562a93c375SAli Bahrami 		if (!ar_extract_bysym(name, fd, adp, ofl, &found, &rej))
857dc0f59e5SAli Bahrami 			return (FALSE);
858dc0f59e5SAli Bahrami 	}
859dc0f59e5SAli Bahrami 
8607c478bd9Sstevel@tonic-gate 	/*
8617c478bd9Sstevel@tonic-gate 	 * If no objects have been found in the archive test for any rejections
8627c478bd9Sstevel@tonic-gate 	 * and if one had occurred issue a warning - its possible a user has
8637c478bd9Sstevel@tonic-gate 	 * pointed at an archive containing the wrong class of elf members.
8647c478bd9Sstevel@tonic-gate 	 */
865a6d4d7d5SRod Evans 	if ((found == 0) && rej.rej_type) {
866de777a60Sab196087 		Conv_reject_desc_buf_t rej_buf;
867de777a60Sab196087 
8681007fd6fSAli Bahrami 		ld_eprintf(ofl, ERR_WARNING, MSG_INTL(reject[rej.rej_type]),
869de777a60Sab196087 		    rej.rej_name ? rej.rej_name : MSG_INTL(MSG_STR_UNKNOWN),
870ba2be530Sab196087 		    conv_reject_desc(&rej, &rej_buf, ld_targ.t_m.m_mach));
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 
874dc0f59e5SAli Bahrami 	return (TRUE);
8757c478bd9Sstevel@tonic-gate }
876