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