xref: /titanic_51/usr/src/cmd/sgs/libld/common/libs.c (revision dcda19f50b2b80bfc622fff718ac04fb0e1cb670)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  *	Copyright (c) 1988 AT&T
24  *	  All Rights Reserved
25  *
26  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 
30 /*
31  * Library processing
32  */
33 #include	<stdio.h>
34 #include	<string.h>
35 #include	<debug.h>
36 #include	"msg.h"
37 #include	"_libld.h"
38 
39 /*
40  * Archive members are typically extracted to resolve an existing undefined
41  * reference.  However, other symbol definitions can cause archive members to
42  * be processed to determine if the archive member provides a more appropriate
43  * definition.  This routine processes the archive member to determine if the
44  * member is really required.
45  *
46  *  i.	Tentative symbols may cause the extraction of an archive member.
47  *	If the archive member has a strong defined symbol it will be used.
48  *	If the archive member simply contains another tentative definition,
49  *	or a defined function symbol, then it will not be used.
50  *
51  *  ii.	A symbol reference may define a hidden or protected visibility.  The
52  *	reference can only be bound to a definition within a relocatable object
53  *	for this restricted visibility to be satisfied.  If the archive member
54  * 	provides a definition of the same symbol type, this definition is
55  *	taken.  The visibility of the defined symbol is irrelevant, as the most
56  *	restrictive visibility of the reference and the definition will be
57  *	applied to the final symbol.
58  */
59 static int
60 process_member(Ar_mem *amp, const char *name, Sym_desc *sdp, Ofl_desc *ofl)
61 {
62 	Sym	*syms, *osym = sdp->sd_sym;
63 	Xword	symn, cnt;
64 	char 	*strs;
65 
66 	/*
67 	 * Find the first symbol table in the archive member, obtain its
68 	 * data buffer and determine the number of global symbols (Note,
69 	 * there must be a symbol table present otherwise the archive would
70 	 * never have been able to generate its own symbol entry for this
71 	 * member).
72 	 */
73 	if (amp->am_syms == NULL) {
74 		Elf_Scn		*scn = NULL;
75 		Shdr		*shdr;
76 		Elf_Data	*data;
77 
78 		while (scn = elf_nextscn(amp->am_elf, scn)) {
79 			if ((shdr = elf_getshdr(scn)) == NULL) {
80 				eprintf(ofl->ofl_lml, ERR_ELF,
81 				    MSG_INTL(MSG_ELF_GETSHDR), amp->am_path);
82 				ofl->ofl_flags |= FLG_OF_FATAL;
83 				return (0);
84 			}
85 			if ((shdr->sh_type == SHT_SYMTAB) ||
86 			    (shdr->sh_type == SHT_DYNSYM))
87 				break;
88 		}
89 		if ((data = elf_getdata(scn, NULL)) == NULL) {
90 			eprintf(ofl->ofl_lml, ERR_ELF,
91 			    MSG_INTL(MSG_ELF_GETDATA), amp->am_path);
92 			ofl->ofl_flags |= FLG_OF_FATAL;
93 			return (0);
94 		}
95 		syms = (Sym *)data->d_buf;
96 		syms += shdr->sh_info;
97 		symn = shdr->sh_size / shdr->sh_entsize;
98 		symn -= shdr->sh_info;
99 
100 		/*
101 		 * Get the data for the associated string table.
102 		 */
103 		if ((scn = elf_getscn(amp->am_elf, (size_t)shdr->sh_link)) ==
104 		    NULL) {
105 			eprintf(ofl->ofl_lml, ERR_ELF,
106 			    MSG_INTL(MSG_ELF_GETSCN), amp->am_path);
107 			ofl->ofl_flags |= FLG_OF_FATAL;
108 			return (0);
109 		}
110 		if ((data = elf_getdata(scn, NULL)) == NULL) {
111 			eprintf(ofl->ofl_lml, ERR_ELF,
112 			    MSG_INTL(MSG_ELF_GETDATA), amp->am_path);
113 			ofl->ofl_flags |= FLG_OF_FATAL;
114 			return (0);
115 		}
116 		strs = data->d_buf;
117 
118 		/*
119 		 * Initialize the archive member structure in case we have to
120 		 * come through here again.
121 		 */
122 		amp->am_syms = syms;
123 		amp->am_strs = strs;
124 		amp->am_symn = symn;
125 	} else {
126 		syms = amp->am_syms;
127 		strs = amp->am_strs;
128 		symn = amp->am_symn;
129 	}
130 
131 	/*
132 	 * Loop through the symbol table entries looking for a match for the
133 	 * original symbol.
134 	 */
135 	for (cnt = 0; cnt < symn; syms++, cnt++) {
136 		Word	shndx;
137 
138 		if ((shndx = syms->st_shndx) == SHN_UNDEF)
139 			continue;
140 
141 		if (osym->st_shndx == SHN_COMMON) {
142 			/*
143 			 * Determine whether a tentative symbol definition
144 			 * should be overridden.
145 			 */
146 			if ((shndx == SHN_ABS) || (shndx == SHN_COMMON) ||
147 			    (ELF_ST_TYPE(syms->st_info) == STT_FUNC))
148 				continue;
149 
150 			/*
151 			 * A historic detail requires that a weak definition
152 			 * within an archive will not override a strong
153 			 * definition (see sym_realtent() resolution and ABI
154 			 * symbol binding description - page 4-27).
155 			 */
156 			if ((ELF_ST_BIND(syms->st_info) == STB_WEAK) &&
157 			    (ELF_ST_BIND(osym->st_info) != STB_WEAK))
158 				continue;
159 		} else {
160 			/*
161 			 * Determine whether a restricted visibility reference
162 			 * should be overridden.  Don't worry about the
163 			 * visibility of the archive member definition, nor
164 			 * whether it is weak or global.  Any definition is
165 			 * better than a binding to an external shared object
166 			 * (which is the only event that must presently exist
167 			 * for us to be here looking for a better alternative).
168 			 */
169 			if (ELF_ST_TYPE(syms->st_info) !=
170 			    ELF_ST_TYPE(osym->st_info))
171 				continue;
172 		}
173 
174 		if (strcmp(strs + syms->st_name, name) == 0)
175 			return (1);
176 	}
177 	return (0);
178 }
179 
180 /*
181  * Create an archive descriptor.  By maintaining a list of archives any
182  * duplicate occurrences of the same archive specified by the user enable us to
183  * pick off where the last processing finished.
184  */
185 Ar_desc *
186 ld_ar_setup(const char *name, Elf *elf, Ofl_desc *ofl)
187 {
188 	Ar_desc *	adp;
189 	size_t		number;
190 	Elf_Arsym *	start;
191 
192 	/*
193 	 * Get the archive symbol table. If this fails, we will
194 	 * ignore this file with a warning message.
195 	 */
196 	if ((start = elf_getarsym(elf, &number)) == NULL) {
197 		if (elf_errno()) {
198 			eprintf(ofl->ofl_lml, ERR_ELF,
199 			    MSG_INTL(MSG_ELF_GETARSYM), name);
200 			ofl->ofl_flags |= FLG_OF_FATAL;
201 		} else
202 			eprintf(ofl->ofl_lml, ERR_WARNING,
203 			    MSG_INTL(MSG_ELF_ARSYM), name);
204 
205 		return (0);
206 	}
207 
208 	/*
209 	 * As this is a new archive reference establish a new descriptor.
210 	 */
211 	if ((adp = libld_malloc(sizeof (Ar_desc))) == NULL)
212 		return ((Ar_desc *)S_ERROR);
213 	adp->ad_name = name;
214 	adp->ad_elf = elf;
215 	adp->ad_start = start;
216 	if ((adp->ad_aux = libld_calloc(sizeof (Ar_aux), number)) == NULL)
217 		return ((Ar_desc *)S_ERROR);
218 
219 	/*
220 	 * Retain any command line options that are applicable to archive
221 	 * extraction in case we have to rescan this archive later.
222 	 */
223 	adp->ad_flags = ofl->ofl_flags1 & MSK_OF1_ARCHIVE;
224 
225 	ofl->ofl_arscnt++;
226 
227 	/*
228 	 * Add this new descriptor to the list of archives.
229 	 */
230 	if (aplist_append(&ofl->ofl_ars, adp, AL_CNT_OFL_LIBS) == NULL)
231 		return ((Ar_desc *)S_ERROR);
232 	else
233 		return (adp);
234 }
235 
236 /*
237  * For each archive descriptor, maintain an `Ar_aux' table to parallel the
238  * archive symbol table (returned from elf_getarsym(3e)).  Use this table to
239  * hold a `Sym_desc' for each symbol (thus reducing the number of
240  * ld_sym_find()'s), and to hold the `Ar_mem' pointer.  The `Ar_mem' element
241  * can have one of three values indicating the state of the archive member
242  * associated with the offset for this symbol table entry:
243  *
244  *  0		indicates that the member has not been processed.
245  *
246  *  FLG_ARMEM_PROC
247  *		indicates that the member has been processed.
248  *
249  *  addr	indicates that the member has been investigated to determine if
250  *		it contained a symbol definition we need, but was found not to
251  *		be a candidate for extraction.  In this case the members
252  *		structure is maintained for possible later use.
253  *
254  * Each time we process an archive member we use its offset value to scan this
255  * `Ar_aux' list.  If the member has been extracted, each entry with the same
256  * offset has its `Ar_mem' pointer set to FLG_ARMEM_PROC.  Thus if we cycle back
257  * through the archive symbol table we will ignore these symbols as they will
258  * have already been added to the output image.  If a member has been processed
259  * but found not to contain a symbol we need, each entry with the same offset
260  * has its `Ar_mem' pointer set to the member structures address.
261  */
262 void
263 ld_ar_member(Ar_desc * adp, Elf_Arsym * arsym, Ar_aux * aup, Ar_mem * amp)
264 {
265 	Elf_Arsym *	_arsym = arsym;
266 	Ar_aux *	_aup = aup;
267 	size_t		_off = arsym->as_off;
268 
269 	if (_arsym != adp->ad_start) {
270 		do {
271 			_arsym--;
272 			_aup--;
273 			if (_arsym->as_off != _off)
274 				break;
275 			_aup->au_mem = amp;
276 		} while (_arsym != adp->ad_start);
277 	}
278 
279 	_arsym = arsym;
280 	_aup = aup;
281 
282 	do {
283 		if (_arsym->as_off != _off)
284 			break;
285 		_aup->au_mem = amp;
286 		_arsym++;
287 		_aup++;
288 	} while (_arsym->as_name);
289 }
290 
291 /*
292  * Data structure to indicate whether a symbol is visible for the purpose
293  * of archive extraction.
294  */
295 static const Boolean
296 sym_vis[STV_NUM] = {
297 	TRUE,		/* STV_DEFAULT */
298 	FALSE,		/* STV_INTERNAL */
299 	FALSE,		/* STV_HIDDEN */
300 	FALSE,		/* STV_PROTECTED */
301 	TRUE,		/* STV_EXPORTED */
302 	TRUE,		/* STV_SINGLETON */
303 	FALSE		/* STV_ELIMINATE */
304 };
305 #if STV_NUM != (STV_ELIMINATE + 1)
306 #error "STV_NUM has grown. Update sym_vis[]."
307 #endif
308 
309 /*
310  * Read the archive symbol table.  For each symbol in the table, determine
311  * whether that symbol satisfies an unresolved reference, tentative reference,
312  * or a reference that expects hidden or protected visibility.  If so, the
313  * corresponding object from the archive is processed.  The archive symbol
314  * table is searched until we go through a complete pass without satisfying any
315  * unresolved symbols
316  */
317 uintptr_t
318 ld_process_archive(const char *name, int fd, Ar_desc *adp, Ofl_desc *ofl)
319 {
320 	Elf_Arsym *	arsym;
321 	Elf_Arhdr *	arhdr;
322 	Elf *		arelf;
323 	Ar_aux *	aup;
324 	Sym_desc *	sdp;
325 	char 		*arname, *arpath;
326 	Xword		ndx;
327 	int		found, again;
328 	int		allexrt = (ofl->ofl_flags1 & FLG_OF1_ALLEXRT) != 0;
329 	uintptr_t	err;
330 	Rej_desc	rej = { 0 };
331 
332 	/*
333 	 * If a fatal error condition has been set there's really no point in
334 	 * processing the archive further.  Having got to this point we have at
335 	 * least established that the archive exists (thus verifying that the
336 	 * command line options that got us to this archive are correct).  Very
337 	 * large archives can take a significant time to process, therefore
338 	 * continuing on from here may significantly delay the fatal error
339 	 * message the user is already set to receive.
340 	 */
341 	if (ofl->ofl_flags & FLG_OF_FATAL)
342 		return (1);
343 
344 	/*
345 	 * If this archive was processed with -z allextract, then all members
346 	 * have already been extracted.
347 	 */
348 	if (adp->ad_elf == NULL)
349 		return (1);
350 
351 	/*
352 	 * Loop through archive symbol table until we make a complete pass
353 	 * without satisfying an unresolved reference.  For each archive
354 	 * symbol, see if there is a symbol with the same name in ld's
355 	 * symbol table.  If so, and if that symbol is still unresolved or
356 	 * tentative, process the corresponding archive member.
357 	 */
358 	found = again = 0;
359 	do {
360 		DBG_CALL(Dbg_file_ar(ofl->ofl_lml, name, again));
361 		DBG_CALL(Dbg_syms_ar_title(ofl->ofl_lml, name, again));
362 
363 		ndx = again = 0;
364 		for (arsym = adp->ad_start, aup = adp->ad_aux; arsym->as_name;
365 		    ++arsym, ++aup, ndx++) {
366 			Rej_desc	_rej = { 0 };
367 			Ar_mem		*amp;
368 			Sym		*sym;
369 			Boolean		visible = TRUE;
370 
371 			/*
372 			 * If the auxiliary members value indicates that this
373 			 * member has been processed then this symbol will have
374 			 * been added to the output file image already or the
375 			 * object was rejected in which case we don't want to
376 			 * process it again.
377 			 */
378 			if (aup->au_mem == FLG_ARMEM_PROC)
379 				continue;
380 
381 			/*
382 			 * If the auxiliary symbol element is non-zero lookup
383 			 * the symbol from the internal symbol table.
384 			 * (But you skip this if allextract is specified.)
385 			 */
386 			if ((allexrt == 0) && ((sdp = aup->au_syms) == NULL)) {
387 				if ((sdp = ld_sym_find(arsym->as_name,
388 				    /* LINTED */
389 				    (Word)arsym->as_hash, 0, ofl)) == NULL) {
390 					DBG_CALL(Dbg_syms_ar_entry(ofl->ofl_lml,
391 					    ndx, arsym));
392 					continue;
393 				}
394 				aup->au_syms = sdp;
395 			}
396 
397 			/*
398 			 * With '-z allextract', all members will be extracted.
399 			 *
400 			 * This archive member is a candidate for extraction if
401 			 * the internal symbol originates from an explicit file,
402 			 * and represents an undefined or tentative symbol.
403 			 *
404 			 * By default, weak references do not cause archive
405 			 * extraction, however the -zweakextract flag overrides
406 			 * this default.
407 			 *
408 			 * If this symbol has already been bound to a versioned
409 			 * shared object, but the shared objects version is not
410 			 * available, then a definition of this symbol from
411 			 * within the archive is a better candidate.  Similarly,
412 			 * if this symbol has been bound to a shared object, but
413 			 * the original reference expected hidden or protected
414 			 * visibility, then a definition of this symbol from
415 			 * within the archive is a better candidate.
416 			 */
417 			if (allexrt == 0) {
418 				Boolean		vers = TRUE;
419 				Ifl_desc	*ifl = sdp->sd_file;
420 
421 				sym = sdp->sd_sym;
422 
423 				if (sdp->sd_ref == REF_DYN_NEED) {
424 					uchar_t	vis;
425 
426 					if (ifl->ifl_vercnt) {
427 						Word		vndx;
428 						Ver_index	*vip;
429 
430 						vndx = sdp->sd_aux->sa_dverndx;
431 						vip = &ifl->ifl_verndx[vndx];
432 						if ((vip->vi_flags &
433 						    FLG_VER_AVAIL) == 0)
434 							vers = FALSE;
435 					}
436 
437 					vis = ELF_ST_VISIBILITY(sym->st_other);
438 					visible = sym_vis[vis];
439 				}
440 
441 				if (((ifl->ifl_flags & FLG_IF_NEEDED) == 0) ||
442 				    (visible && vers &&
443 				    (sym->st_shndx != SHN_UNDEF) &&
444 				    (sym->st_shndx != SHN_COMMON)) ||
445 				    ((ELF_ST_BIND(sym->st_info) == STB_WEAK) &&
446 				    (!(ofl->ofl_flags1 & FLG_OF1_WEAKEXT)))) {
447 					DBG_CALL(Dbg_syms_ar_entry(ofl->ofl_lml,
448 					    ndx, arsym));
449 					continue;
450 				}
451 			}
452 
453 			/*
454 			 * Determine if we have already extracted this member,
455 			 * and if so reuse the Ar_mem information.
456 			 */
457 			if ((amp = aup->au_mem) != 0) {
458 				arelf = amp->am_elf;
459 				arname = amp->am_name;
460 				arpath = amp->am_path;
461 			} else {
462 				size_t	len;
463 
464 				/*
465 				 * Set up a new elf descriptor for this member.
466 				 */
467 				if (elf_rand(adp->ad_elf, arsym->as_off) !=
468 				    arsym->as_off) {
469 					eprintf(ofl->ofl_lml, ERR_ELF,
470 					    MSG_INTL(MSG_ELF_ARMEM), name,
471 					    EC_WORD(arsym->as_off), ndx,
472 					    demangle(arsym->as_name));
473 					ofl->ofl_flags |= FLG_OF_FATAL;
474 					return (0);
475 				}
476 
477 				if ((arelf = elf_begin(fd, ELF_C_READ,
478 				    adp->ad_elf)) == NULL) {
479 					eprintf(ofl->ofl_lml, ERR_ELF,
480 					    MSG_INTL(MSG_ELF_BEGIN), name);
481 					ofl->ofl_flags |= FLG_OF_FATAL;
482 					return (0);
483 				}
484 
485 				/*
486 				 * Construct the member filename.
487 				 */
488 				if ((arhdr = elf_getarhdr(arelf)) == NULL) {
489 					eprintf(ofl->ofl_lml, ERR_ELF,
490 					    MSG_INTL(MSG_ELF_GETARHDR), name);
491 					ofl->ofl_flags |= FLG_OF_FATAL;
492 					return (0);
493 				}
494 				arname = arhdr->ar_name;
495 
496 				/*
497 				 * Construct the members full pathname, using
498 				 * the format "%s(%s)".
499 				 */
500 				len = strlen(name) + strlen(arname) + 3;
501 				if ((arpath = libld_malloc(len)) == NULL)
502 					return (S_ERROR);
503 				(void) snprintf(arpath, len,
504 				    MSG_ORIG(MSG_FMT_ARMEM), name, arname);
505 
506 				/*
507 				 * Determine whether the support library wishes
508 				 * to process this open.  See comments in
509 				 * ld_process_open().
510 				 */
511 				ld_sup_open(ofl, (const char **)&arpath,
512 				    (const char **)&arname, &fd,
513 				    (FLG_IF_EXTRACT | FLG_IF_NEEDED),
514 				    &arelf, adp->ad_elf, arsym->as_off,
515 				    elf_kind(arelf));
516 
517 				/*
518 				 * An ELF descriptor of zero indicates that
519 				 * the archive member should be ignored.
520 				 */
521 				if (arelf == NULL) {
522 					aup->au_mem = FLG_ARMEM_PROC;
523 					continue;
524 				}
525 			}
526 
527 			/*
528 			 * The symbol for which this archive member is being
529 			 * processed may provide a better alternative to the
530 			 * symbol that is presently known.  Two cases are
531 			 * covered:
532 			 *
533 			 *  i.	The present symbol represents tentative data.
534 			 *	The archive member may provide a data
535 			 *	definition symbol.
536 			 *  ii.	The present symbol represents a reference that
537 			 *	has seen a definition within a shared object
538 			 *	dependency, but the reference expects to be
539 			 *	reduced to hidden or protected visibility.
540 			 */
541 			if ((allexrt == 0) &&
542 			    ((sym->st_shndx == SHN_COMMON) ||
543 			    (visible == FALSE))) {
544 				/*
545 				 * If we don't already have a member structure
546 				 * allocate one.
547 				 */
548 				if (!amp) {
549 					if ((amp = libld_calloc(sizeof (Ar_mem),
550 					    1)) == NULL)
551 						return (S_ERROR);
552 					amp->am_elf = arelf;
553 					amp->am_name = arname;
554 					amp->am_path = arpath;
555 				}
556 				DBG_CALL(Dbg_syms_ar_checking(ofl->ofl_lml,
557 				    ndx, arsym, arname));
558 				if ((err = process_member(amp, arsym->as_name,
559 				    sdp, ofl)) == S_ERROR)
560 					return (S_ERROR);
561 
562 				/*
563 				 * If it turns out that we don't need this
564 				 * member simply initialize all other auxiliary
565 				 * entries that match this offset with this
566 				 * members address.  In this way we can resuse
567 				 * this information if we recurse back to this
568 				 * symbol.
569 				 */
570 				if (err == 0) {
571 					if (aup->au_mem == NULL)
572 						ld_ar_member(adp, arsym,
573 						    aup, amp);
574 					continue;
575 				}
576 			}
577 
578 			/*
579 			 * Process the archive member.  Retain any error for
580 			 * return to the caller.
581 			 */
582 			DBG_CALL(Dbg_syms_ar_resolve(ofl->ofl_lml, ndx, arsym,
583 			    arname, allexrt));
584 			if ((err = (uintptr_t)ld_process_ifl(arpath, NULL, fd,
585 			    arelf, (FLG_IF_EXTRACT | FLG_IF_NEEDED), ofl,
586 			    &_rej)) == S_ERROR)
587 				return (S_ERROR);
588 
589 			/*
590 			 * If this member is rejected maintain the first
591 			 * rejection error for possible later display.  Keep the
592 			 * member as extracted so that we don't try and process
593 			 * it again on a rescan.
594 			 */
595 			if (_rej.rej_type) {
596 				if (rej.rej_type == 0) {
597 					rej.rej_type = _rej.rej_type;
598 					rej.rej_info = _rej.rej_info;
599 					rej.rej_name = (const char *)arpath;
600 				}
601 				ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC);
602 				continue;
603 			}
604 
605 			/*
606 			 * Indicate that the extracted member is in use.  This
607 			 * enables debugging diags, and indicates that a further
608 			 * rescan of all archives may be necessary.
609 			 */
610 			found = 1;
611 			ofl->ofl_flags1 |= FLG_OF1_EXTRACT;
612 			adp->ad_flags |= FLG_ARD_EXTRACT;
613 
614 			/*
615 			 * If not under '-z allextract' signal the need to
616 			 * rescan this archive.
617 			 */
618 			if (allexrt == 0)
619 				again = 1;
620 
621 			ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC);
622 			DBG_CALL(Dbg_util_nl(ofl->ofl_lml, DBG_NL_STD));
623 		}
624 	} while (again);
625 
626 	/*
627 	 * If no objects have been found in the archive test for any rejections
628 	 * and if one had occurred issue a warning - its possible a user has
629 	 * pointed at an archive containing the wrong class of elf members.
630 	 */
631 	if ((found == 0) && rej.rej_type) {
632 		Conv_reject_desc_buf_t rej_buf;
633 
634 		eprintf(ofl->ofl_lml, ERR_WARNING,
635 		    MSG_INTL(reject[rej.rej_type]),
636 		    rej.rej_name ? rej.rej_name : MSG_INTL(MSG_STR_UNKNOWN),
637 		    conv_reject_desc(&rej, &rej_buf, ld_targ.t_m.m_mach));
638 	}
639 
640 	/*
641 	 * If this archive was extracted by -z allextract, the ar_aux table
642 	 * and elf descriptor can be freed.  Set ad_elf to NULL to mark the
643 	 * archive is completely processed.
644 	 */
645 	if (allexrt) {
646 		(void) elf_end(adp->ad_elf);
647 		adp->ad_elf = NULL;
648 	}
649 
650 	return (1);
651 }
652