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