xref: /illumos-gate/usr/src/cmd/sgs/libld/common/util.c (revision fb12490a)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215aefb655Srie 
227257d1b4Sraf /*
231007fd6fSAli Bahrami  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
247257d1b4Sraf  */
257257d1b4Sraf 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  *	Copyright (c) 1988 AT&T
287c478bd9Sstevel@tonic-gate  *	  All Rights Reserved
297c478bd9Sstevel@tonic-gate  */
307257d1b4Sraf 
317d732bb0SJohn Levon /*
327d732bb0SJohn Levon  * Copyright (c) 2018, Joyent, Inc.
337d732bb0SJohn Levon  */
347d732bb0SJohn Levon 
357c478bd9Sstevel@tonic-gate /*
367c478bd9Sstevel@tonic-gate  * Utility functions
377c478bd9Sstevel@tonic-gate  */
387257d1b4Sraf #include <unistd.h>
397257d1b4Sraf #include <stdio.h>
407257d1b4Sraf #include <stdarg.h>
417257d1b4Sraf #include <string.h>
427257d1b4Sraf #include <fcntl.h>
437257d1b4Sraf #include <sys/types.h>
447257d1b4Sraf #include <sys/mman.h>
457257d1b4Sraf #include <errno.h>
467257d1b4Sraf #include <sgs.h>
477257d1b4Sraf #include <libintl.h>
487257d1b4Sraf #include <debug.h>
497257d1b4Sraf #include "msg.h"
507257d1b4Sraf #include "_libld.h"
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * Determine if a shared object definition structure already exists and if
547c478bd9Sstevel@tonic-gate  * not create one.  These definitions provide for recording information
557c478bd9Sstevel@tonic-gate  * regarding shared objects that are still to be processed.  Once processed
567c478bd9Sstevel@tonic-gate  * shared objects are maintained on the ofl_sos list.  The information
577c478bd9Sstevel@tonic-gate  * recorded in this structure includes:
587c478bd9Sstevel@tonic-gate  *
597c478bd9Sstevel@tonic-gate  *  o	DT_USED requirements.  In these cases definitions are added during
607c478bd9Sstevel@tonic-gate  *	mapfile processing of `-' entries (see map_dash()).
617c478bd9Sstevel@tonic-gate  *
627c478bd9Sstevel@tonic-gate  *  o	implicit NEEDED entries.  As shared objects are processed from the
637c478bd9Sstevel@tonic-gate  *	command line so any of their dependencies are recorded in these
647c478bd9Sstevel@tonic-gate  *	structures for later processing (see process_dynamic()).
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  *  o	version requirements.  Any explicit shared objects that have version
677c478bd9Sstevel@tonic-gate  *	dependencies on other objects have their version requirements recorded.
687c478bd9Sstevel@tonic-gate  *	In these cases definitions are added during mapfile processing of `-'
697c478bd9Sstevel@tonic-gate  *	entries (see map_dash()).  Also, shared objects may have versioning
707c478bd9Sstevel@tonic-gate  *	requirements on their NEEDED entries.  These cases are added during
717c478bd9Sstevel@tonic-gate  *	their version processing (see vers_need_process()).
727c478bd9Sstevel@tonic-gate  *
737c478bd9Sstevel@tonic-gate  *	Note: Both process_dynamic() and vers_need_process() may generate the
747c478bd9Sstevel@tonic-gate  *	initial version definition structure because you can't rely on what
757c478bd9Sstevel@tonic-gate  *	section (.dynamic or .SUNW_version) may be processed first from	any
767c478bd9Sstevel@tonic-gate  *	input file.
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate Sdf_desc *
sdf_find(const char * name,APlist * alp)7957ef7aa9SRod Evans sdf_find(const char *name, APlist *alp)
807c478bd9Sstevel@tonic-gate {
8157ef7aa9SRod Evans 	Aliste		idx;
827c478bd9Sstevel@tonic-gate 	Sdf_desc	*sdf;
837c478bd9Sstevel@tonic-gate 
8457ef7aa9SRod Evans 	for (APLIST_TRAVERSE(alp, idx, sdf))
857c478bd9Sstevel@tonic-gate 		if (strcmp(name, sdf->sdf_name) == 0)
867c478bd9Sstevel@tonic-gate 			return (sdf);
877c478bd9Sstevel@tonic-gate 
880e233487SRod Evans 	return (NULL);
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate Sdf_desc *
sdf_add(const char * name,APlist ** alpp)9257ef7aa9SRod Evans sdf_add(const char *name, APlist **alpp)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	Sdf_desc	*sdf;
957c478bd9Sstevel@tonic-gate 
96*fb12490aSRichard Lowe 	if ((sdf = libld_calloc(1, sizeof (Sdf_desc))) == NULL)
977c478bd9Sstevel@tonic-gate 		return ((Sdf_desc *)S_ERROR);
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	sdf->sdf_name = name;
1007c478bd9Sstevel@tonic-gate 
10157ef7aa9SRod Evans 	if (aplist_append(alpp, sdf, AL_CNT_OFL_LIBS) == NULL)
1027c478bd9Sstevel@tonic-gate 		return ((Sdf_desc *)S_ERROR);
10357ef7aa9SRod Evans 
10457ef7aa9SRod Evans 	return (sdf);
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * Add a string, separated by a colon, to an existing string.  Typically used
1097c478bd9Sstevel@tonic-gate  * to maintain filter, rpath and audit names, of which there is normally only
1107c478bd9Sstevel@tonic-gate  * one string supplied anyway.
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate char *
add_string(char * old,char * str)1137c478bd9Sstevel@tonic-gate add_string(char *old, char *str)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate 	char	*new;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	if (old) {
1187c478bd9Sstevel@tonic-gate 		char	*_str;
1197c478bd9Sstevel@tonic-gate 		size_t	len;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 		/*
1227c478bd9Sstevel@tonic-gate 		 * If an original string exists, make sure this new string
1237c478bd9Sstevel@tonic-gate 		 * doesn't get duplicated.
1247c478bd9Sstevel@tonic-gate 		 */
1257c478bd9Sstevel@tonic-gate 		if ((_str = strstr(old, str)) != NULL) {
1267c478bd9Sstevel@tonic-gate 			if (((_str == old) ||
1277c478bd9Sstevel@tonic-gate 			    (*(_str - 1) == *(MSG_ORIG(MSG_STR_COLON)))) &&
1287c478bd9Sstevel@tonic-gate 			    (_str += strlen(str)) &&
1297c478bd9Sstevel@tonic-gate 			    ((*_str == '\0') ||
1307c478bd9Sstevel@tonic-gate 			    (*_str == *(MSG_ORIG(MSG_STR_COLON)))))
1317c478bd9Sstevel@tonic-gate 				return (old);
1327c478bd9Sstevel@tonic-gate 		}
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 		len = strlen(old) + strlen(str) + 2;
1350e233487SRod Evans 		if ((new = libld_calloc(1, len)) == NULL)
1367c478bd9Sstevel@tonic-gate 			return ((char *)S_ERROR);
1377c478bd9Sstevel@tonic-gate 		(void) snprintf(new, len, MSG_ORIG(MSG_FMT_COLPATH), old, str);
1387c478bd9Sstevel@tonic-gate 	} else {
1390e233487SRod Evans 		if ((new = libld_malloc(strlen(str) + 1)) == NULL)
1407c478bd9Sstevel@tonic-gate 			return ((char *)S_ERROR);
1417c478bd9Sstevel@tonic-gate 		(void) strcpy(new, str);
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	return (new);
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate 
147cdcc71c0SAli Bahrami /*
148cdcc71c0SAli Bahrami  * The GNU ld '-wrap=XXX' and '--wrap=XXX' options correspond to our
149cdcc71c0SAli Bahrami  * '-z wrap=XXX'. When str2chr() does this conversion, we end up with
150cdcc71c0SAli Bahrami  * the return character set to 'z' and optarg set to 'XXX'. This callback
151cdcc71c0SAli Bahrami  * changes optarg to include the missing wrap= prefix.
152cdcc71c0SAli Bahrami  *
153cdcc71c0SAli Bahrami  * exit:
154cdcc71c0SAli Bahrami  *	Returns c on success, or '?' on error.
155cdcc71c0SAli Bahrami  */
156cdcc71c0SAli Bahrami static int
str2chr_wrap_cb(int c)157cdcc71c0SAli Bahrami str2chr_wrap_cb(int c)
158cdcc71c0SAli Bahrami {
159cdcc71c0SAli Bahrami 	char    *str;
160cdcc71c0SAli Bahrami 	size_t  len = MSG_ARG_WRAP_SIZE + strlen(optarg) + 1;
161cdcc71c0SAli Bahrami 
162cdcc71c0SAli Bahrami 	if ((str = libld_malloc(len)) == NULL)
163cdcc71c0SAli Bahrami 		return ('?');
164cdcc71c0SAli Bahrami 	(void) snprintf(str, len, MSG_ORIG(MSG_FMT_STRCAT),
165cdcc71c0SAli Bahrami 	    MSG_ORIG(MSG_ARG_WRAP), optarg);
166cdcc71c0SAli Bahrami 	optarg = str;
167cdcc71c0SAli Bahrami 	return (c);
168cdcc71c0SAli Bahrami }
169cdcc71c0SAli Bahrami 
17092a02081SRod Evans /*
171c5accfb2SRichard Lowe  * Determine whether this string, possibly with an associated option, should
172c5accfb2SRichard Lowe  * be translated to an option character.  If so, update the optind and optarg
173c5accfb2SRichard Lowe  * and optopt as described for short options in getopt(3c).
174cdcc71c0SAli Bahrami  *
175cdcc71c0SAli Bahrami  * entry:
176cdcc71c0SAli Bahrami  *	lml - Link map list for debug messages
177cdcc71c0SAli Bahrami  *	ndx - Starting optind for current item
178cdcc71c0SAli Bahrami  *	argc, argv - Command line arguments
179cdcc71c0SAli Bahrami  *	arg - Option to be examined
180cdcc71c0SAli Bahrami  *	c, opt - Option character (c) and corresponding long name (opt)
181cdcc71c0SAli Bahrami  *	optsz - 0 if option does not accept a value. If option does
182cdcc71c0SAli Bahrami  *		accept a value, strlen(opt), giving the offset to the
183cdcc71c0SAli Bahrami  *		value if the option and value are combined in one string.
184cdcc71c0SAli Bahrami  *	cbfunc - NULL, or pointer to function to call if a translation is
185cdcc71c0SAli Bahrami  *		successful.
18692a02081SRod Evans  */
18792a02081SRod Evans static int
str2chr(Lm_list * lml,int ndx,int argc,char ** argv,char * arg,int c,const char * opt,size_t optsz,int (* cbfunc)(int))18892a02081SRod Evans str2chr(Lm_list *lml, int ndx, int argc, char **argv, char *arg, int c,
1897d732bb0SJohn Levon     const char *opt, size_t optsz, int (*cbfunc)(int))
19092a02081SRod Evans {
19192a02081SRod Evans 	if (optsz == 0) {
19292a02081SRod Evans 		/*
19392a02081SRod Evans 		 * Compare a single option (ie. there's no associated option
19492a02081SRod Evans 		 * argument).
19592a02081SRod Evans 		 */
19692a02081SRod Evans 		if (strcmp(arg, opt) == 0) {
19792a02081SRod Evans 			DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c));
19892a02081SRod Evans 			optind += 1;
199c5accfb2SRichard Lowe 			optopt = c;
20092a02081SRod Evans 			return (c);
20192a02081SRod Evans 		}
20244a646f1SRichard Lowe 	} else if ((strcmp(arg, opt) == 0) ||
20344a646f1SRichard Lowe 	    ((arg[optsz] == '=') && strncmp(arg, opt, optsz) == 0)) {
20492a02081SRod Evans 		/*
20592a02081SRod Evans 		 * Otherwise, compare the option name, which may be
20692a02081SRod Evans 		 * concatenated with the option argument.
20792a02081SRod Evans 		 */
20892a02081SRod Evans 		DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c));
20992a02081SRod Evans 
21092a02081SRod Evans 		if (arg[optsz] == '\0') {
21192a02081SRod Evans 			/*
21292a02081SRod Evans 			 * Optarg is the next argument (white space separated).
21392a02081SRod Evans 			 * Make sure an optarg is available, and if not return
21492a02081SRod Evans 			 * a failure to prevent any fall-through to the generic
21592a02081SRod Evans 			 * getopt() processing.
216c5accfb2SRichard Lowe 			 *
217c5accfb2SRichard Lowe 			 * Since we'll be completely failing this option we
218c5accfb2SRichard Lowe 			 * don't want to update optopt with the translation,
219c5accfb2SRichard Lowe 			 * but also need to set it to _something_.  Setting it
220c5accfb2SRichard Lowe 			 * to the '-' of the argument causes us to behave
221c5accfb2SRichard Lowe 			 * correctly.
22292a02081SRod Evans 			 */
22392a02081SRod Evans 			if ((++optind + 1) > argc) {
224c5accfb2SRichard Lowe 				optopt = arg[0];
22592a02081SRod Evans 				return ('?');
22692a02081SRod Evans 			}
22792a02081SRod Evans 			optarg = argv[optind];
22892a02081SRod Evans 			optind++;
22992a02081SRod Evans 		} else {
23092a02081SRod Evans 			/*
23192a02081SRod Evans 			 * GNU option/option argument pairs can be represented
23292a02081SRod Evans 			 * with a "=" separator.  If this is the case, remove
23392a02081SRod Evans 			 * the separator.
23492a02081SRod Evans 			 */
23592a02081SRod Evans 			optarg = &arg[optsz];
23692a02081SRod Evans 			optind++;
23792a02081SRod Evans 			if (*optarg == '=') {
238c5accfb2SRichard Lowe 				if (*(++optarg) == '\0') {
239c5accfb2SRichard Lowe 					optopt = arg[0];
24092a02081SRod Evans 					return ('?');
241c5accfb2SRichard Lowe 				}
24292a02081SRod Evans 			}
24392a02081SRod Evans 		}
244cdcc71c0SAli Bahrami 
245cdcc71c0SAli Bahrami 		if (cbfunc != NULL)
246cdcc71c0SAli Bahrami 			c = (*cbfunc)(c);
247c5accfb2SRichard Lowe 		optopt = c;
24892a02081SRod Evans 		return (c);
24992a02081SRod Evans 	}
25092a02081SRod Evans 	return (0);
25192a02081SRod Evans }
25292a02081SRod Evans 
25392a02081SRod Evans /*
25492a02081SRod Evans  * Parse an individual option.  The intent of this function is to determine if
25592a02081SRod Evans  * any known, non-Solaris options have been passed to ld(1).  This condition
25692a02081SRod Evans  * can occur as a result of build configuration tools, because of users
25792a02081SRod Evans  * familiarity with other systems, or simply the users preferences.  If a known
25892a02081SRod Evans  * non-Solaris option can be determined, translate that option into the Solaris
25992a02081SRod Evans  * counterpart.
26092a02081SRod Evans  *
26192a02081SRod Evans  * This function will probably never be a complete solution, as new, non-Solaris
26292a02081SRod Evans  * options are discovered, their translation will have to be added.  Other
26392a02081SRod Evans  * non-Solaris options are incompatible with the Solaris link-editor, and will
26492a02081SRod Evans  * never be recognized.  We support what we can.
26592a02081SRod Evans  */
26692a02081SRod Evans int
ld_getopt(Lm_list * lml,int ndx,int argc,char ** argv)26792a02081SRod Evans ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
26892a02081SRod Evans {
26992a02081SRod Evans 	int	c;
27092a02081SRod Evans 
27192a02081SRod Evans 	if ((optind < argc) && argv[optind] && (argv[optind][0] == '-')) {
27292a02081SRod Evans 		char	*arg = &argv[optind][1];
27392a02081SRod Evans 
27492a02081SRod Evans 		switch (*arg) {
27592a02081SRod Evans 		case 'r':
27692a02081SRod Evans 			/* Translate -rpath <optarg> to -R <optarg> */
27792a02081SRod Evans 			if ((c = str2chr(lml, ndx, argc, argv, arg, 'R',
27892a02081SRod Evans 			    MSG_ORIG(MSG_ARG_T_RPATH),
279cdcc71c0SAli Bahrami 			    MSG_ARG_T_RPATH_SIZE, NULL)) != 0) {
28092a02081SRod Evans 				return (c);
28192a02081SRod Evans 			}
28292a02081SRod Evans 			break;
28392a02081SRod Evans 		case 's':
28492a02081SRod Evans 			/* Translate -shared to -G */
28592a02081SRod Evans 			if ((c = str2chr(lml, ndx, argc, argv, arg, 'G',
286cdcc71c0SAli Bahrami 			    MSG_ORIG(MSG_ARG_T_SHARED), 0, NULL)) != 0) {
28792a02081SRod Evans 				return (c);
28892a02081SRod Evans 
28992a02081SRod Evans 			/* Translate -soname <optarg> to -h <optarg> */
29092a02081SRod Evans 			} else if ((c = str2chr(lml, ndx, argc, argv, arg, 'h',
29192a02081SRod Evans 			    MSG_ORIG(MSG_ARG_T_SONAME),
292cdcc71c0SAli Bahrami 			    MSG_ARG_T_SONAME_SIZE, NULL)) != 0) {
293cdcc71c0SAli Bahrami 				return (c);
294cdcc71c0SAli Bahrami 			}
295cdcc71c0SAli Bahrami 			break;
296cdcc71c0SAli Bahrami 		case 'w':
297cdcc71c0SAli Bahrami 			/* Translate -wrap to -z wrap= */
298cdcc71c0SAli Bahrami 			if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
299cdcc71c0SAli Bahrami 			    MSG_ORIG(MSG_ARG_T_WRAP) + 1,
300cdcc71c0SAli Bahrami 			    MSG_ARG_T_WRAP_SIZE - 1, str2chr_wrap_cb)) != 0) {
30192a02081SRod Evans 				return (c);
30292a02081SRod Evans 			}
30392a02081SRod Evans 			break;
304551cffe3SAli Bahrami 		case '(':
305551cffe3SAli Bahrami 			/*
306551cffe3SAli Bahrami 			 * Translate -( to -z rescan-start
307551cffe3SAli Bahrami 			 */
308551cffe3SAli Bahrami 			if ((c = str2chr(lml, ndx, argc, argv,
309cdcc71c0SAli Bahrami 			    arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0, NULL)) !=
310cdcc71c0SAli Bahrami 			    0) {
311551cffe3SAli Bahrami 				optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_START);
312551cffe3SAli Bahrami 				return (c);
313551cffe3SAli Bahrami 			}
314551cffe3SAli Bahrami 			break;
315551cffe3SAli Bahrami 		case ')':
316551cffe3SAli Bahrami 			/*
317551cffe3SAli Bahrami 			 * Translate -) to -z rescan-end
318551cffe3SAli Bahrami 			 */
319551cffe3SAli Bahrami 			if ((c = str2chr(lml, ndx, argc, argv,
320cdcc71c0SAli Bahrami 			    arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0, NULL)) !=
321cdcc71c0SAli Bahrami 			    0) {
322551cffe3SAli Bahrami 				optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_END);
323551cffe3SAli Bahrami 				return (c);
324551cffe3SAli Bahrami 			}
325551cffe3SAli Bahrami 			break;
32692a02081SRod Evans 		case '-':
32792a02081SRod Evans 			switch (*(arg + 1)) {
32892a02081SRod Evans 			case 'a':
32992a02081SRod Evans 				/*
33092a02081SRod Evans 				 * Translate --allow-multiple-definition to
33192a02081SRod Evans 				 * -zmuldefs
33292a02081SRod Evans 				 */
33392a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
334cdcc71c0SAli Bahrami 				    MSG_ORIG(MSG_ARG_T_MULDEFS), 0, NULL)) !=
335cdcc71c0SAli Bahrami 				    0) {
33692a02081SRod Evans 					optarg =
33792a02081SRod Evans 					    (char *)MSG_ORIG(MSG_ARG_MULDEFS);
33892a02081SRod Evans 					return (c);
33992a02081SRod Evans 
34092a02081SRod Evans 				/*
34192a02081SRod Evans 				 * Translate --auxiliary <optarg> to
34292a02081SRod Evans 				 * -f <optarg>
34392a02081SRod Evans 				 */
34492a02081SRod Evans 				} else if ((c = str2chr(lml, argc, ndx, argv,
34592a02081SRod Evans 				    arg, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR),
346cdcc71c0SAli Bahrami 				    MSG_ARG_T_AUXFLTR_SIZE, NULL)) != 0) {
34792a02081SRod Evans 					return (c);
34892a02081SRod Evans 				}
34992a02081SRod Evans 				break;
35092a02081SRod Evans 			case 'd':
35192a02081SRod Evans 				/*
35292a02081SRod Evans 				 * Translate --dynamic-linker <optarg> to
35392a02081SRod Evans 				 * -I <optarg>
35492a02081SRod Evans 				 */
35592a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'I',
35692a02081SRod Evans 				    MSG_ORIG(MSG_ARG_T_INTERP),
357cdcc71c0SAli Bahrami 				    MSG_ARG_T_INTERP_SIZE, NULL)) != 0) {
35892a02081SRod Evans 					return (c);
35992a02081SRod Evans 				}
36092a02081SRod Evans 				break;
36192a02081SRod Evans 			case 'e':
36292a02081SRod Evans 				/* Translate --entry <optarg> to -e <optarg> */
36392a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'e',
36492a02081SRod Evans 				    MSG_ORIG(MSG_ARG_T_ENTRY),
365cdcc71c0SAli Bahrami 				    MSG_ARG_T_ENTRY_SIZE, NULL)) != 0) {
36692a02081SRod Evans 					return (c);
36792a02081SRod Evans 				}
368551cffe3SAli Bahrami 				/*
369551cffe3SAli Bahrami 				 * Translate --end-group to -z rescan-end
370551cffe3SAli Bahrami 				 */
371551cffe3SAli Bahrami 				if ((c = str2chr(lml, ndx, argc, argv,
372cdcc71c0SAli Bahrami 				    arg, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP),
373cdcc71c0SAli Bahrami 				    0, NULL)) != 0) {
374551cffe3SAli Bahrami 					optarg = (char *)
375551cffe3SAli Bahrami 					    MSG_ORIG(MSG_ARG_RESCAN_END);
376551cffe3SAli Bahrami 					return (c);
377551cffe3SAli Bahrami 				}
37892a02081SRod Evans 				break;
37992a02081SRod Evans 			case 'f':
3801007fd6fSAli Bahrami 				/*
3811007fd6fSAli Bahrami 				 * Translate --fatal-warnings to
3821007fd6fSAli Bahrami 				 * -z fatal-warnings.
3831007fd6fSAli Bahrami 				 */
3841007fd6fSAli Bahrami 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
3851007fd6fSAli Bahrami 				    MSG_ORIG(MSG_ARG_T_FATWARN),
3861007fd6fSAli Bahrami 				    0, NULL)) != 0) {
3871007fd6fSAli Bahrami 					optarg = (char *)
3881007fd6fSAli Bahrami 					    MSG_ORIG(MSG_ARG_FATWARN);
3891007fd6fSAli Bahrami 					return (c);
3901007fd6fSAli Bahrami 				}
39192a02081SRod Evans 				/* Translate --filter <optarg> to -F <optarg> */
39292a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'F',
39392a02081SRod Evans 				    MSG_ORIG(MSG_ARG_T_STDFLTR),
394cdcc71c0SAli Bahrami 				    MSG_ARG_T_STDFLTR_SIZE, NULL)) != 0) {
39592a02081SRod Evans 					return (c);
39692a02081SRod Evans 				}
39792a02081SRod Evans 				break;
39892a02081SRod Evans 			case 'h':
39992a02081SRod Evans 				/* Translate --help to -zhelp */
40092a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
401cdcc71c0SAli Bahrami 				    MSG_ORIG(MSG_ARG_T_HELP), 0, NULL)) !=
402cdcc71c0SAli Bahrami 				    0) {
40392a02081SRod Evans 					optarg = (char *)MSG_ORIG(MSG_ARG_HELP);
40492a02081SRod Evans 					return (c);
40592a02081SRod Evans 				}
40692a02081SRod Evans 				break;
40792a02081SRod Evans 			case 'l':
40892a02081SRod Evans 				/*
40992a02081SRod Evans 				 * Translate --library <optarg> to -l <optarg>
41092a02081SRod Evans 				 */
41192a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'l',
41292a02081SRod Evans 				    MSG_ORIG(MSG_ARG_T_LIBRARY),
413cdcc71c0SAli Bahrami 				    MSG_ARG_T_LIBRARY_SIZE, NULL)) != 0) {
41492a02081SRod Evans 					return (c);
41592a02081SRod Evans 
41692a02081SRod Evans 				/*
41792a02081SRod Evans 				 * Translate --library-path <optarg> to
41892a02081SRod Evans 				 * -L <optarg>
41992a02081SRod Evans 				 */
42092a02081SRod Evans 				} else if ((c = str2chr(lml, ndx, argc, argv,
42192a02081SRod Evans 				    arg, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH),
422cdcc71c0SAli Bahrami 				    MSG_ARG_T_LIBPATH_SIZE, NULL)) != 0) {
42392a02081SRod Evans 					return (c);
42492a02081SRod Evans 				}
42592a02081SRod Evans 				break;
42692a02081SRod Evans 			case 'n':
4271007fd6fSAli Bahrami 				/*
4281007fd6fSAli Bahrami 				 * Translate --no-fatal-warnings to
4291007fd6fSAli Bahrami 				 * -z nofatal-warnings.
4301007fd6fSAli Bahrami 				 */
4311007fd6fSAli Bahrami 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
4321007fd6fSAli Bahrami 				    MSG_ORIG(MSG_ARG_T_NOFATWARN),
4331007fd6fSAli Bahrami 				    0, NULL)) != 0) {
4341007fd6fSAli Bahrami 					optarg = (char *)
4351007fd6fSAli Bahrami 					    MSG_ORIG(MSG_ARG_NOFATWARN);
4361007fd6fSAli Bahrami 					return (c);
4371007fd6fSAli Bahrami 				}
4381007fd6fSAli Bahrami 
43992a02081SRod Evans 				/* Translate --no-undefined to -zdefs */
44092a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
441cdcc71c0SAli Bahrami 				    MSG_ORIG(MSG_ARG_T_NOUNDEF), 0, NULL)) !=
442cdcc71c0SAli Bahrami 				    0) {
44392a02081SRod Evans 					optarg = (char *)MSG_ORIG(MSG_ARG_DEFS);
44492a02081SRod Evans 					return (c);
44592a02081SRod Evans 
44692a02081SRod Evans 				/*
44792a02081SRod Evans 				 * Translate --no-whole-archive to
44892a02081SRod Evans 				 * -z defaultextract
44992a02081SRod Evans 				 */
45092a02081SRod Evans 				} else if ((c = str2chr(lml, ndx, argc, argv,
451cdcc71c0SAli Bahrami 				    arg, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC),
452cdcc71c0SAli Bahrami 				    0, NULL)) != 0) {
45392a02081SRod Evans 					optarg =
45492a02081SRod Evans 					    (char *)MSG_ORIG(MSG_ARG_DFLEXTRT);
45592a02081SRod Evans 					return (c);
45692a02081SRod Evans 				}
45792a02081SRod Evans 				break;
45892a02081SRod Evans 			case 'o':
45992a02081SRod Evans 				/* Translate --output <optarg> to -o <optarg> */
46092a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'o',
46192a02081SRod Evans 				    MSG_ORIG(MSG_ARG_T_OUTPUT),
462cdcc71c0SAli Bahrami 				    MSG_ARG_T_OUTPUT_SIZE, NULL)) != 0) {
46392a02081SRod Evans 					return (c);
46492a02081SRod Evans 				}
46592a02081SRod Evans 				break;
46692a02081SRod Evans 			case 'r':
46792a02081SRod Evans 				/* Translate --relocatable to -r */
46892a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'r',
469cdcc71c0SAli Bahrami 				    MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0,
470cdcc71c0SAli Bahrami 				    NULL)) != 0) {
47192a02081SRod Evans 					return (c);
47292a02081SRod Evans 				}
47392a02081SRod Evans 				break;
47492a02081SRod Evans 			case 's':
47592a02081SRod Evans 				/* Translate --strip-all to -s */
47692a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 's',
477cdcc71c0SAli Bahrami 				    MSG_ORIG(MSG_ARG_T_STRIP), 0, NULL)) !=
478cdcc71c0SAli Bahrami 				    0) {
47992a02081SRod Evans 					return (c);
48092a02081SRod Evans 				}
481551cffe3SAli Bahrami 				/*
482551cffe3SAli Bahrami 				 * Translate --start-group to -z rescan-start
483551cffe3SAli Bahrami 				 */
484551cffe3SAli Bahrami 				if ((c = str2chr(lml, ndx, argc, argv,
485cdcc71c0SAli Bahrami 				    arg, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP),
486cdcc71c0SAli Bahrami 				    0, NULL)) != 0) {
487551cffe3SAli Bahrami 					optarg = (char *)
488551cffe3SAli Bahrami 					    MSG_ORIG(MSG_ARG_RESCAN_START);
489551cffe3SAli Bahrami 					return (c);
490551cffe3SAli Bahrami 				}
49192a02081SRod Evans 				break;
49292a02081SRod Evans 			case 'u':
49392a02081SRod Evans 				/*
49492a02081SRod Evans 				 * Translate --undefined <optarg> to
49592a02081SRod Evans 				 * -u <optarg>
49692a02081SRod Evans 				 */
49792a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'u',
49892a02081SRod Evans 				    MSG_ORIG(MSG_ARG_T_UNDEF),
499cdcc71c0SAli Bahrami 				    MSG_ARG_T_UNDEF_SIZE, NULL)) != 0) {
50092a02081SRod Evans 					return (c);
50192a02081SRod Evans 				}
50292a02081SRod Evans 				break;
50392a02081SRod Evans 			case 'v':
50492a02081SRod Evans 				/* Translate --version to -V */
50592a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv, arg, 'V',
506cdcc71c0SAli Bahrami 				    MSG_ORIG(MSG_ARG_T_VERSION), 0, NULL)) !=
507cdcc71c0SAli Bahrami 				    0) {
50892a02081SRod Evans 					return (c);
50992a02081SRod Evans 				}
51092a02081SRod Evans 				break;
51192a02081SRod Evans 			case 'w':
51292a02081SRod Evans 				/*
51392a02081SRod Evans 				 * Translate --whole-archive to -z alltextract
51492a02081SRod Evans 				 */
51592a02081SRod Evans 				if ((c = str2chr(lml, ndx, argc, argv,
516cdcc71c0SAli Bahrami 				    arg, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC),
517cdcc71c0SAli Bahrami 				    0, NULL)) != 0) {
51892a02081SRod Evans 					optarg =
51992a02081SRod Evans 					    (char *)MSG_ORIG(MSG_ARG_ALLEXTRT);
52092a02081SRod Evans 					return (c);
52192a02081SRod Evans 				}
522cdcc71c0SAli Bahrami 				/*
523cdcc71c0SAli Bahrami 				 * Translate --wrap to -z wrap=
524cdcc71c0SAli Bahrami 				 */
525cdcc71c0SAli Bahrami 				if ((c = str2chr(lml, ndx, argc, argv,
526cdcc71c0SAli Bahrami 				    arg, 'z', MSG_ORIG(MSG_ARG_T_WRAP),
527cdcc71c0SAli Bahrami 				    MSG_ARG_T_WRAP_SIZE, str2chr_wrap_cb)) !=
528cdcc71c0SAli Bahrami 				    0) {
529cdcc71c0SAli Bahrami 					return (c);
530cdcc71c0SAli Bahrami 				}
53192a02081SRod Evans 				break;
53292a02081SRod Evans 			}
53392a02081SRod Evans 			break;
53492a02081SRod Evans 		}
53592a02081SRod Evans 	}
536cdcc71c0SAli Bahrami 
53792a02081SRod Evans 	if ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
53892a02081SRod Evans 		/*
53992a02081SRod Evans 		 * It is possible that a "-Wl," argument has been used to
54092a02081SRod Evans 		 * specify an option.  This isn't advertized ld(1) syntax, but
54192a02081SRod Evans 		 * compiler drivers and configuration tools, have been known to
54292a02081SRod Evans 		 * pass this compiler option to ld(1).  Strip off the "-Wl,"
54392a02081SRod Evans 		 * prefix and pass the option through.
54492a02081SRod Evans 		 */
54592a02081SRod Evans 		if ((c == 'W') && (strncmp(optarg,
54692a02081SRod Evans 		    MSG_ORIG(MSG_ARG_T_WL), MSG_ARG_T_WL_SIZE) == 0)) {
54792a02081SRod Evans 			DBG_CALL(Dbg_args_Wldel(lml, ndx, optarg));
54892a02081SRod Evans 			c = optarg[MSG_ARG_T_WL_SIZE];
54992a02081SRod Evans 			optarg += MSG_ARG_T_WL_SIZE + 1;
55092a02081SRod Evans 		}
55192a02081SRod Evans 	}
55292a02081SRod Evans 
55392a02081SRod Evans 	return (c);
55492a02081SRod Evans }
55592a02081SRod Evans 
5567c478bd9Sstevel@tonic-gate /*
557e64d0ff9SAli Bahrami  * A compare routine for Isd_node AVL trees.
5587c478bd9Sstevel@tonic-gate  */
5596b3ba5bdSAli Bahrami int
isdavl_compare(const void * n1,const void * n2)5606b3ba5bdSAli Bahrami isdavl_compare(const void *n1, const void *n2)
5616b3ba5bdSAli Bahrami {
5626b3ba5bdSAli Bahrami 	uint_t		hash1, hash2;
5636b3ba5bdSAli Bahrami 	const char	*st1, *st2;
5646b3ba5bdSAli Bahrami 	int		rc;
5656b3ba5bdSAli Bahrami 
5666b3ba5bdSAli Bahrami 	hash1 = ((Isd_node *)n1)->isd_hash;
5676b3ba5bdSAli Bahrami 	hash2 = ((Isd_node *)n2)->isd_hash;
5686b3ba5bdSAli Bahrami 
5696b3ba5bdSAli Bahrami 	if (hash1 > hash2)
5706b3ba5bdSAli Bahrami 		return (1);
5716b3ba5bdSAli Bahrami 	if (hash1 < hash2)
5726b3ba5bdSAli Bahrami 		return (-1);
5736b3ba5bdSAli Bahrami 
574e64d0ff9SAli Bahrami 	st1 = ((Isd_node *)n1)->isd_name;
575e64d0ff9SAli Bahrami 	st2 = ((Isd_node *)n2)->isd_name;
5766b3ba5bdSAli Bahrami 
5776b3ba5bdSAli Bahrami 	rc = strcmp(st1, st2);
5786b3ba5bdSAli Bahrami 	if (rc > 0)
5796b3ba5bdSAli Bahrami 		return (1);
5806b3ba5bdSAli Bahrami 	if (rc < 0)
5816b3ba5bdSAli Bahrami 		return (-1);
5826b3ba5bdSAli Bahrami 	return (0);
5836b3ba5bdSAli Bahrami }
5847c478bd9Sstevel@tonic-gate 
5856b3ba5bdSAli Bahrami /*
5866b3ba5bdSAli Bahrami  * Messaging support - funnel everything through dgettext().
5876b3ba5bdSAli Bahrami  */
5887c478bd9Sstevel@tonic-gate const char *
_libld_msg(Msg mid)5897c478bd9Sstevel@tonic-gate _libld_msg(Msg mid)
5907c478bd9Sstevel@tonic-gate {
5917257d1b4Sraf 	return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate /*
5957c478bd9Sstevel@tonic-gate  * Determine whether a symbol name should be demangled.
5967c478bd9Sstevel@tonic-gate  */
5977c478bd9Sstevel@tonic-gate const char *
demangle(const char * name)5987c478bd9Sstevel@tonic-gate demangle(const char *name)
5997c478bd9Sstevel@tonic-gate {
6005aefb655Srie 	if (demangle_flag)
6015aefb655Srie 		return (Elf_demangle_name(name));
6027c478bd9Sstevel@tonic-gate 	else
6037c478bd9Sstevel@tonic-gate 		return (name);
6047c478bd9Sstevel@tonic-gate }
60508278a5eSRod Evans 
60608278a5eSRod Evans /*
60708278a5eSRod Evans  * Compare a series of platform or machine hardware names.
60808278a5eSRod Evans  */
60908278a5eSRod Evans int
cap_names_match(Alist * alp1,Alist * alp2)61008278a5eSRod Evans cap_names_match(Alist *alp1, Alist *alp2)
61108278a5eSRod Evans {
61208278a5eSRod Evans 	Capstr		*capstr1;
61308278a5eSRod Evans 	Aliste		idx1;
61408278a5eSRod Evans 	int		match = 0;
61508278a5eSRod Evans 	Word		nitems;
61608278a5eSRod Evans 
61708278a5eSRod Evans 	if ((nitems = alist_nitems(alp1)) != alist_nitems(alp2))
61808278a5eSRod Evans 		return (1);
61908278a5eSRod Evans 
62008278a5eSRod Evans 	for (ALIST_TRAVERSE(alp1, idx1, capstr1)) {
62108278a5eSRod Evans 		Capstr		*capstr2;
622*fb12490aSRichard Lowe 		Aliste		idx2;
62308278a5eSRod Evans 
62408278a5eSRod Evans 		for (ALIST_TRAVERSE(alp2, idx2, capstr2)) {
62508278a5eSRod Evans 			if (strcmp(capstr1->cs_str, capstr2->cs_str))
62608278a5eSRod Evans 				continue;
62708278a5eSRod Evans 
62808278a5eSRod Evans 			match++;
62908278a5eSRod Evans 			break;
63008278a5eSRod Evans 		}
63108278a5eSRod Evans 	}
63208278a5eSRod Evans 
63308278a5eSRod Evans 	if (nitems == match)
63408278a5eSRod Evans 		return (0);
63508278a5eSRod Evans 
63608278a5eSRod Evans 	return (1);
63708278a5eSRod Evans }
638