xref: /illumos-gate/usr/src/cmd/sgs/libld/common/util.c (revision f52943a93040563107b95bccb9db87d9971ef47d)
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) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  *	Copyright (c) 1988 AT&T
28  *	  All Rights Reserved
29  */
30 
31 /*
32  * Copyright (c) 2018, Joyent, Inc.
33  */
34 
35 /*
36  * Utility functions
37  */
38 #include <unistd.h>
39 #include <stdio.h>
40 #include <stdarg.h>
41 #include <string.h>
42 #include <fcntl.h>
43 #include <sys/types.h>
44 #include <sys/mman.h>
45 #include <errno.h>
46 #include <sgs.h>
47 #include <libintl.h>
48 #include <debug.h>
49 #include "msg.h"
50 #include "_libld.h"
51 
52 /*
53  * libld_malloc() and dz_map() are used for both performance and for ease of
54  * programming:
55  *
56  * Performance:
57  *	The link-edit is a short lived process which doesn't really free much
58  *	of the dynamic memory that it requests.  Because of this, it is more
59  *	important to optimize for quick memory allocations than the
60  *	re-usability of the memory.
61  *
62  *	By also mmaping blocks of pages in from /dev/zero we don't need to
63  *	waste the overhead of zeroing out these pages for calloc() requests.
64  *
65  * Memory Management:
66  *	By doing all libld memory management through the ld_malloc routine
67  *	it's much easier to free up all memory at the end by simply unmaping
68  *	all of the blocks that were mapped in through dz_map().  This is much
69  *	simpler then trying to track all of the libld structures that were
70  *	dynamically allocate and are actually pointers into the ELF files.
71  *
72  *	It's important that we can free up all of our dynamic memory because
73  *	libld is used by ld.so.1 when it performs dlopen()'s of relocatable
74  *	objects.
75  *
76  * Format:
77  *	The memory blocks for each allocation store the size of the allocation
78  *	in the first 8 bytes of the block.  The pointer that is returned by
79  *	libld_malloc() is actually the address of (block + 8):
80  *
81  *		(addr - 8)	block_size
82  *		(addr)		<allocated block>
83  *
84  *	The size is retained in order to implement realloc(), and to perform
85  *	the required memcpy().  8 bytes are uses, as the memory area returned
86  *	by libld_malloc() must be 8 byte-aligned.  Even in a 32-bit environment,
87  *	u_longlog_t pointers are employed.
88  *
89  * Map anonymous memory via MAP_ANON (added in Solaris 8).
90  */
91 static void *
92 dz_map(size_t size)
93 {
94 	void	*addr;
95 
96 	if ((addr = mmap(0, size, (PROT_READ | PROT_WRITE | PROT_EXEC),
97 	    (MAP_PRIVATE | MAP_ANON), -1, 0)) == MAP_FAILED) {
98 		int	err = errno;
99 		eprintf(NULL, ERR_FATAL, MSG_INTL(MSG_SYS_MMAPANON),
100 		    strerror(err));
101 		return (MAP_FAILED);
102 	}
103 	return (addr);
104 }
105 
106 void *
107 libld_malloc(size_t size)
108 {
109 	Ld_heap		*chp = ld_heap;
110 	void		*vptr;
111 	size_t		asize = size + HEAPALIGN;
112 
113 	/*
114 	 * If this is the first allocation, or the allocation request is greater
115 	 * than the current free space available, allocate a new heap.
116 	 */
117 	if ((chp == NULL) ||
118 	    (((size_t)chp->lh_end - (size_t)chp->lh_free) <= asize)) {
119 		Ld_heap	*nhp;
120 		size_t	hsize = (size_t)S_ROUND(sizeof (Ld_heap), HEAPALIGN);
121 		size_t	tsize = (size_t)S_ROUND((asize + hsize), HEAPALIGN);
122 
123 		/*
124 		 * Allocate a block that is at minimum 'HEAPBLOCK' size
125 		 */
126 		if (tsize < HEAPBLOCK)
127 			tsize = HEAPBLOCK;
128 
129 		if ((nhp = dz_map(tsize)) == MAP_FAILED)
130 			return (NULL);
131 
132 		nhp->lh_next = chp;
133 		nhp->lh_free = (void *)((size_t)nhp + hsize);
134 		nhp->lh_end = (void *)((size_t)nhp + tsize);
135 
136 		ld_heap = chp = nhp;
137 	}
138 	vptr = chp->lh_free;
139 
140 	/*
141 	 * Assign size to head of allocated block (used by realloc), and
142 	 * memory arena as then next 8-byte aligned offset.
143 	 */
144 	*((size_t *)vptr) = size;
145 	vptr = (void *)((size_t)vptr + HEAPALIGN);
146 
147 	/*
148 	 * Increment free to point to next available block
149 	 */
150 	chp->lh_free = (void *)S_ROUND((size_t)chp->lh_free + asize,
151 	    HEAPALIGN);
152 
153 	return (vptr);
154 }
155 
156 void *
157 libld_realloc(void *ptr, size_t size)
158 {
159 	size_t	psize;
160 	void	*vptr;
161 
162 	if (ptr == NULL)
163 		return (libld_malloc(size));
164 
165 	/*
166 	 * Size of the allocated blocks is stored *just* before the blocks
167 	 * address.
168 	 */
169 	psize = *((size_t *)((size_t)ptr - HEAPALIGN));
170 
171 	/*
172 	 * If the block actually fits then just return.
173 	 */
174 	if (size <= psize)
175 		return (ptr);
176 
177 	if ((vptr = libld_malloc(size)) != NULL)
178 		(void) memcpy(vptr, ptr, psize);
179 
180 	return (vptr);
181 }
182 
183 void
184 /* ARGSUSED 0 */
185 libld_free(void *ptr)
186 {
187 }
188 
189 /*
190  * Determine if a shared object definition structure already exists and if
191  * not create one.  These definitions provide for recording information
192  * regarding shared objects that are still to be processed.  Once processed
193  * shared objects are maintained on the ofl_sos list.  The information
194  * recorded in this structure includes:
195  *
196  *  o	DT_USED requirements.  In these cases definitions are added during
197  *	mapfile processing of `-' entries (see map_dash()).
198  *
199  *  o	implicit NEEDED entries.  As shared objects are processed from the
200  *	command line so any of their dependencies are recorded in these
201  *	structures for later processing (see process_dynamic()).
202  *
203  *  o	version requirements.  Any explicit shared objects that have version
204  *	dependencies on other objects have their version requirements recorded.
205  *	In these cases definitions are added during mapfile processing of `-'
206  *	entries (see map_dash()).  Also, shared objects may have versioning
207  *	requirements on their NEEDED entries.  These cases are added during
208  *	their version processing (see vers_need_process()).
209  *
210  *	Note: Both process_dynamic() and vers_need_process() may generate the
211  *	initial version definition structure because you can't rely on what
212  *	section (.dynamic or .SUNW_version) may be processed first from	any
213  *	input file.
214  */
215 Sdf_desc *
216 sdf_find(const char *name, APlist *alp)
217 {
218 	Aliste		idx;
219 	Sdf_desc	*sdf;
220 
221 	for (APLIST_TRAVERSE(alp, idx, sdf))
222 		if (strcmp(name, sdf->sdf_name) == 0)
223 			return (sdf);
224 
225 	return (NULL);
226 }
227 
228 Sdf_desc *
229 sdf_add(const char *name, APlist **alpp)
230 {
231 	Sdf_desc	*sdf;
232 
233 	if ((sdf = libld_calloc(sizeof (Sdf_desc), 1)) == NULL)
234 		return ((Sdf_desc *)S_ERROR);
235 
236 	sdf->sdf_name = name;
237 
238 	if (aplist_append(alpp, sdf, AL_CNT_OFL_LIBS) == NULL)
239 		return ((Sdf_desc *)S_ERROR);
240 
241 	return (sdf);
242 }
243 
244 /*
245  * Add a string, separated by a colon, to an existing string.  Typically used
246  * to maintain filter, rpath and audit names, of which there is normally only
247  * one string supplied anyway.
248  */
249 char *
250 add_string(char *old, char *str)
251 {
252 	char	*new;
253 
254 	if (old) {
255 		char	*_str;
256 		size_t	len;
257 
258 		/*
259 		 * If an original string exists, make sure this new string
260 		 * doesn't get duplicated.
261 		 */
262 		if ((_str = strstr(old, str)) != NULL) {
263 			if (((_str == old) ||
264 			    (*(_str - 1) == *(MSG_ORIG(MSG_STR_COLON)))) &&
265 			    (_str += strlen(str)) &&
266 			    ((*_str == '\0') ||
267 			    (*_str == *(MSG_ORIG(MSG_STR_COLON)))))
268 				return (old);
269 		}
270 
271 		len = strlen(old) + strlen(str) + 2;
272 		if ((new = libld_calloc(1, len)) == NULL)
273 			return ((char *)S_ERROR);
274 		(void) snprintf(new, len, MSG_ORIG(MSG_FMT_COLPATH), old, str);
275 	} else {
276 		if ((new = libld_malloc(strlen(str) + 1)) == NULL)
277 			return ((char *)S_ERROR);
278 		(void) strcpy(new, str);
279 	}
280 
281 	return (new);
282 }
283 
284 /*
285  * The GNU ld '-wrap=XXX' and '--wrap=XXX' options correspond to our
286  * '-z wrap=XXX'. When str2chr() does this conversion, we end up with
287  * the return character set to 'z' and optarg set to 'XXX'. This callback
288  * changes optarg to include the missing wrap= prefix.
289  *
290  * exit:
291  *	Returns c on success, or '?' on error.
292  */
293 static int
294 str2chr_wrap_cb(int c)
295 {
296 	char    *str;
297 	size_t  len = MSG_ARG_WRAP_SIZE + strlen(optarg) + 1;
298 
299 	if ((str = libld_malloc(len)) == NULL)
300 		return ('?');
301 	(void) snprintf(str, len, MSG_ORIG(MSG_FMT_STRCAT),
302 	    MSG_ORIG(MSG_ARG_WRAP), optarg);
303 	optarg = str;
304 	return (c);
305 }
306 
307 /*
308  * Determine whether this string, possibly with an associated option, should
309  * be translated to an option character.  If so, update the optind and optarg
310  * and optopt as described for short options in getopt(3c).
311  *
312  * entry:
313  *	lml - Link map list for debug messages
314  *	ndx - Starting optind for current item
315  *	argc, argv - Command line arguments
316  *	arg - Option to be examined
317  *	c, opt - Option character (c) and corresponding long name (opt)
318  *	optsz - 0 if option does not accept a value. If option does
319  *		accept a value, strlen(opt), giving the offset to the
320  *		value if the option and value are combined in one string.
321  *	cbfunc - NULL, or pointer to function to call if a translation is
322  *		successful.
323  */
324 static int
325 str2chr(Lm_list *lml, int ndx, int argc, char **argv, char *arg, int c,
326     const char *opt, size_t optsz, int (*cbfunc)(int))
327 {
328 	if (optsz == 0) {
329 		/*
330 		 * Compare a single option (ie. there's no associated option
331 		 * argument).
332 		 */
333 		if (strcmp(arg, opt) == 0) {
334 			DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c));
335 			optind += 1;
336 			optopt = c;
337 			return (c);
338 		}
339 	} else if ((strcmp(arg, opt) == 0) ||
340 	    ((arg[optsz] == '=') && strncmp(arg, opt, optsz) == 0)) {
341 		/*
342 		 * Otherwise, compare the option name, which may be
343 		 * concatenated with the option argument.
344 		 */
345 		DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c));
346 
347 		if (arg[optsz] == '\0') {
348 			/*
349 			 * Optarg is the next argument (white space separated).
350 			 * Make sure an optarg is available, and if not return
351 			 * a failure to prevent any fall-through to the generic
352 			 * getopt() processing.
353 			 *
354 			 * Since we'll be completely failing this option we
355 			 * don't want to update optopt with the translation,
356 			 * but also need to set it to _something_.  Setting it
357 			 * to the '-' of the argument causes us to behave
358 			 * correctly.
359 			 */
360 			if ((++optind + 1) > argc) {
361 				optopt = arg[0];
362 				return ('?');
363 			}
364 			optarg = argv[optind];
365 			optind++;
366 		} else {
367 			/*
368 			 * GNU option/option argument pairs can be represented
369 			 * with a "=" separator.  If this is the case, remove
370 			 * the separator.
371 			 */
372 			optarg = &arg[optsz];
373 			optind++;
374 			if (*optarg == '=') {
375 				if (*(++optarg) == '\0') {
376 					optopt = arg[0];
377 					return ('?');
378 				}
379 			}
380 		}
381 
382 		if (cbfunc != NULL)
383 			c = (*cbfunc)(c);
384 		optopt = c;
385 		return (c);
386 	}
387 	return (0);
388 }
389 
390 /*
391  * Parse an individual option.  The intent of this function is to determine if
392  * any known, non-Solaris options have been passed to ld(1).  This condition
393  * can occur as a result of build configuration tools, because of users
394  * familiarity with other systems, or simply the users preferences.  If a known
395  * non-Solaris option can be determined, translate that option into the Solaris
396  * counterpart.
397  *
398  * This function will probably never be a complete solution, as new, non-Solaris
399  * options are discovered, their translation will have to be added.  Other
400  * non-Solaris options are incompatible with the Solaris link-editor, and will
401  * never be recognized.  We support what we can.
402  */
403 int
404 ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
405 {
406 	int	c;
407 
408 	if ((optind < argc) && argv[optind] && (argv[optind][0] == '-')) {
409 		char	*arg = &argv[optind][1];
410 
411 		switch (*arg) {
412 		case 'r':
413 			/* Translate -rpath <optarg> to -R <optarg> */
414 			if ((c = str2chr(lml, ndx, argc, argv, arg, 'R',
415 			    MSG_ORIG(MSG_ARG_T_RPATH),
416 			    MSG_ARG_T_RPATH_SIZE, NULL)) != 0) {
417 				return (c);
418 			}
419 			break;
420 		case 's':
421 			/* Translate -shared to -G */
422 			if ((c = str2chr(lml, ndx, argc, argv, arg, 'G',
423 			    MSG_ORIG(MSG_ARG_T_SHARED), 0, NULL)) != 0) {
424 				return (c);
425 
426 			/* Translate -soname <optarg> to -h <optarg> */
427 			} else if ((c = str2chr(lml, ndx, argc, argv, arg, 'h',
428 			    MSG_ORIG(MSG_ARG_T_SONAME),
429 			    MSG_ARG_T_SONAME_SIZE, NULL)) != 0) {
430 				return (c);
431 			}
432 			break;
433 		case 'w':
434 			/* Translate -wrap to -z wrap= */
435 			if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
436 			    MSG_ORIG(MSG_ARG_T_WRAP) + 1,
437 			    MSG_ARG_T_WRAP_SIZE - 1, str2chr_wrap_cb)) != 0) {
438 				return (c);
439 			}
440 			break;
441 		case '(':
442 			/*
443 			 * Translate -( to -z rescan-start
444 			 */
445 			if ((c = str2chr(lml, ndx, argc, argv,
446 			    arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0, NULL)) !=
447 			    0) {
448 				optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_START);
449 				return (c);
450 			}
451 			break;
452 		case ')':
453 			/*
454 			 * Translate -) to -z rescan-end
455 			 */
456 			if ((c = str2chr(lml, ndx, argc, argv,
457 			    arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0, NULL)) !=
458 			    0) {
459 				optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_END);
460 				return (c);
461 			}
462 			break;
463 		case '-':
464 			switch (*(arg + 1)) {
465 			case 'a':
466 				/*
467 				 * Translate --allow-multiple-definition to
468 				 * -zmuldefs
469 				 */
470 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
471 				    MSG_ORIG(MSG_ARG_T_MULDEFS), 0, NULL)) !=
472 				    0) {
473 					optarg =
474 					    (char *)MSG_ORIG(MSG_ARG_MULDEFS);
475 					return (c);
476 
477 				/*
478 				 * Translate --auxiliary <optarg> to
479 				 * -f <optarg>
480 				 */
481 				} else if ((c = str2chr(lml, argc, ndx, argv,
482 				    arg, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR),
483 				    MSG_ARG_T_AUXFLTR_SIZE, NULL)) != 0) {
484 					return (c);
485 				}
486 				break;
487 			case 'd':
488 				/*
489 				 * Translate --dynamic-linker <optarg> to
490 				 * -I <optarg>
491 				 */
492 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'I',
493 				    MSG_ORIG(MSG_ARG_T_INTERP),
494 				    MSG_ARG_T_INTERP_SIZE, NULL)) != 0) {
495 					return (c);
496 				}
497 				break;
498 			case 'e':
499 				/* Translate --entry <optarg> to -e <optarg> */
500 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'e',
501 				    MSG_ORIG(MSG_ARG_T_ENTRY),
502 				    MSG_ARG_T_ENTRY_SIZE, NULL)) != 0) {
503 					return (c);
504 				}
505 				/*
506 				 * Translate --end-group to -z rescan-end
507 				 */
508 				if ((c = str2chr(lml, ndx, argc, argv,
509 				    arg, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP),
510 				    0, NULL)) != 0) {
511 					optarg = (char *)
512 					    MSG_ORIG(MSG_ARG_RESCAN_END);
513 					return (c);
514 				}
515 				break;
516 			case 'f':
517 				/*
518 				 * Translate --fatal-warnings to
519 				 * -z fatal-warnings.
520 				 */
521 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
522 				    MSG_ORIG(MSG_ARG_T_FATWARN),
523 				    0, NULL)) != 0) {
524 					optarg = (char *)
525 					    MSG_ORIG(MSG_ARG_FATWARN);
526 					return (c);
527 				}
528 				/* Translate --filter <optarg> to -F <optarg> */
529 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'F',
530 				    MSG_ORIG(MSG_ARG_T_STDFLTR),
531 				    MSG_ARG_T_STDFLTR_SIZE, NULL)) != 0) {
532 					return (c);
533 				}
534 				break;
535 			case 'h':
536 				/* Translate --help to -zhelp */
537 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
538 				    MSG_ORIG(MSG_ARG_T_HELP), 0, NULL)) !=
539 				    0) {
540 					optarg = (char *)MSG_ORIG(MSG_ARG_HELP);
541 					return (c);
542 				}
543 				break;
544 			case 'l':
545 				/*
546 				 * Translate --library <optarg> to -l <optarg>
547 				 */
548 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'l',
549 				    MSG_ORIG(MSG_ARG_T_LIBRARY),
550 				    MSG_ARG_T_LIBRARY_SIZE, NULL)) != 0) {
551 					return (c);
552 
553 				/*
554 				 * Translate --library-path <optarg> to
555 				 * -L <optarg>
556 				 */
557 				} else if ((c = str2chr(lml, ndx, argc, argv,
558 				    arg, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH),
559 				    MSG_ARG_T_LIBPATH_SIZE, NULL)) != 0) {
560 					return (c);
561 				}
562 				break;
563 			case 'n':
564 				/*
565 				 * Translate --no-fatal-warnings to
566 				 * -z nofatal-warnings.
567 				 */
568 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
569 				    MSG_ORIG(MSG_ARG_T_NOFATWARN),
570 				    0, NULL)) != 0) {
571 					optarg = (char *)
572 					    MSG_ORIG(MSG_ARG_NOFATWARN);
573 					return (c);
574 				}
575 
576 				/* Translate --no-undefined to -zdefs */
577 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
578 				    MSG_ORIG(MSG_ARG_T_NOUNDEF), 0, NULL)) !=
579 				    0) {
580 					optarg = (char *)MSG_ORIG(MSG_ARG_DEFS);
581 					return (c);
582 
583 				/*
584 				 * Translate --no-whole-archive to
585 				 * -z defaultextract
586 				 */
587 				} else if ((c = str2chr(lml, ndx, argc, argv,
588 				    arg, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC),
589 				    0, NULL)) != 0) {
590 					optarg =
591 					    (char *)MSG_ORIG(MSG_ARG_DFLEXTRT);
592 					return (c);
593 				}
594 				break;
595 			case 'o':
596 				/* Translate --output <optarg> to -o <optarg> */
597 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'o',
598 				    MSG_ORIG(MSG_ARG_T_OUTPUT),
599 				    MSG_ARG_T_OUTPUT_SIZE, NULL)) != 0) {
600 					return (c);
601 				}
602 				break;
603 			case 'r':
604 				/* Translate --relocatable to -r */
605 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'r',
606 				    MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0,
607 				    NULL)) != 0) {
608 					return (c);
609 				}
610 				break;
611 			case 's':
612 				/* Translate --strip-all to -s */
613 				if ((c = str2chr(lml, ndx, argc, argv, arg, 's',
614 				    MSG_ORIG(MSG_ARG_T_STRIP), 0, NULL)) !=
615 				    0) {
616 					return (c);
617 				}
618 				/*
619 				 * Translate --start-group to -z rescan-start
620 				 */
621 				if ((c = str2chr(lml, ndx, argc, argv,
622 				    arg, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP),
623 				    0, NULL)) != 0) {
624 					optarg = (char *)
625 					    MSG_ORIG(MSG_ARG_RESCAN_START);
626 					return (c);
627 				}
628 				break;
629 			case 'u':
630 				/*
631 				 * Translate --undefined <optarg> to
632 				 * -u <optarg>
633 				 */
634 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'u',
635 				    MSG_ORIG(MSG_ARG_T_UNDEF),
636 				    MSG_ARG_T_UNDEF_SIZE, NULL)) != 0) {
637 					return (c);
638 				}
639 				break;
640 			case 'v':
641 				/* Translate --version to -V */
642 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'V',
643 				    MSG_ORIG(MSG_ARG_T_VERSION), 0, NULL)) !=
644 				    0) {
645 					return (c);
646 				}
647 				break;
648 			case 'w':
649 				/*
650 				 * Translate --whole-archive to -z alltextract
651 				 */
652 				if ((c = str2chr(lml, ndx, argc, argv,
653 				    arg, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC),
654 				    0, NULL)) != 0) {
655 					optarg =
656 					    (char *)MSG_ORIG(MSG_ARG_ALLEXTRT);
657 					return (c);
658 				}
659 				/*
660 				 * Translate --wrap to -z wrap=
661 				 */
662 				if ((c = str2chr(lml, ndx, argc, argv,
663 				    arg, 'z', MSG_ORIG(MSG_ARG_T_WRAP),
664 				    MSG_ARG_T_WRAP_SIZE, str2chr_wrap_cb)) !=
665 				    0) {
666 					return (c);
667 				}
668 				break;
669 			}
670 			break;
671 		}
672 	}
673 
674 	if ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
675 		/*
676 		 * It is possible that a "-Wl," argument has been used to
677 		 * specify an option.  This isn't advertized ld(1) syntax, but
678 		 * compiler drivers and configuration tools, have been known to
679 		 * pass this compiler option to ld(1).  Strip off the "-Wl,"
680 		 * prefix and pass the option through.
681 		 */
682 		if ((c == 'W') && (strncmp(optarg,
683 		    MSG_ORIG(MSG_ARG_T_WL), MSG_ARG_T_WL_SIZE) == 0)) {
684 			DBG_CALL(Dbg_args_Wldel(lml, ndx, optarg));
685 			c = optarg[MSG_ARG_T_WL_SIZE];
686 			optarg += MSG_ARG_T_WL_SIZE + 1;
687 		}
688 	}
689 
690 	return (c);
691 }
692 
693 /*
694  * A compare routine for Isd_node AVL trees.
695  */
696 int
697 isdavl_compare(const void *n1, const void *n2)
698 {
699 	uint_t		hash1, hash2;
700 	const char	*st1, *st2;
701 	int		rc;
702 
703 	hash1 = ((Isd_node *)n1)->isd_hash;
704 	hash2 = ((Isd_node *)n2)->isd_hash;
705 
706 	if (hash1 > hash2)
707 		return (1);
708 	if (hash1 < hash2)
709 		return (-1);
710 
711 	st1 = ((Isd_node *)n1)->isd_name;
712 	st2 = ((Isd_node *)n2)->isd_name;
713 
714 	rc = strcmp(st1, st2);
715 	if (rc > 0)
716 		return (1);
717 	if (rc < 0)
718 		return (-1);
719 	return (0);
720 }
721 
722 /*
723  * Messaging support - funnel everything through dgettext().
724  */
725 const char *
726 _libld_msg(Msg mid)
727 {
728 	return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
729 }
730 
731 /*
732  * Determine whether a symbol name should be demangled.
733  */
734 const char *
735 demangle(const char *name)
736 {
737 	if (demangle_flag)
738 		return (Elf_demangle_name(name));
739 	else
740 		return (name);
741 }
742 
743 /*
744  * Compare a series of platform or machine hardware names.
745  */
746 int
747 cap_names_match(Alist *alp1, Alist *alp2)
748 {
749 	Capstr		*capstr1;
750 	Aliste		idx1;
751 	int		match = 0;
752 	Word		nitems;
753 
754 	if ((nitems = alist_nitems(alp1)) != alist_nitems(alp2))
755 		return (1);
756 
757 	for (ALIST_TRAVERSE(alp1, idx1, capstr1)) {
758 		Capstr		*capstr2;
759 		Aliste 		idx2;
760 
761 		for (ALIST_TRAVERSE(alp2, idx2, capstr2)) {
762 			if (strcmp(capstr1->cs_str, capstr2->cs_str))
763 				continue;
764 
765 			match++;
766 			break;
767 		}
768 	}
769 
770 	if (nitems == match)
771 		return (0);
772 
773 	return (1);
774 }
775