xref: /onnv-gate/usr/src/cmd/sgs/ld/common/ld.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*0Sstevel@tonic-gate 
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include	<stdio.h>
30*0Sstevel@tonic-gate #include	<stdlib.h>
31*0Sstevel@tonic-gate #include	<unistd.h>
32*0Sstevel@tonic-gate #include	<stdarg.h>
33*0Sstevel@tonic-gate #include	<string.h>
34*0Sstevel@tonic-gate #include	<errno.h>
35*0Sstevel@tonic-gate #include	<fcntl.h>
36*0Sstevel@tonic-gate #include	<libintl.h>
37*0Sstevel@tonic-gate #include	<locale.h>
38*0Sstevel@tonic-gate #include	<fcntl.h>
39*0Sstevel@tonic-gate #include	<dlfcn.h>
40*0Sstevel@tonic-gate #include	"conv.h"
41*0Sstevel@tonic-gate #include	"libld.h"
42*0Sstevel@tonic-gate #include	"msg.h"
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate /*
46*0Sstevel@tonic-gate  * The following prevent us from having to include ctype.h which defines these
47*0Sstevel@tonic-gate  * functions as macros which reference the __ctype[] array.  Go through .plt's
48*0Sstevel@tonic-gate  * to get to these functions in libc rather than have every invocation of ld
49*0Sstevel@tonic-gate  * have to suffer the R_SPARC_COPY overhead of the __ctype[] array.
50*0Sstevel@tonic-gate  */
51*0Sstevel@tonic-gate extern int	isspace(int);
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate /*
55*0Sstevel@tonic-gate  * Determine whether we need the Elf32 or Elf64 libld.
56*0Sstevel@tonic-gate  */
57*0Sstevel@tonic-gate static int
58*0Sstevel@tonic-gate determine_class(int argc, char ** argv)
59*0Sstevel@tonic-gate {
60*0Sstevel@tonic-gate 	unsigned char	class = 0;
61*0Sstevel@tonic-gate 	int		c;
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate getmore:
64*0Sstevel@tonic-gate 	/*
65*0Sstevel@tonic-gate 	 * Skip options.
66*0Sstevel@tonic-gate 	 *
67*0Sstevel@tonic-gate 	 * The only option we're interested in is -64, which enforces a 64-bit
68*0Sstevel@tonic-gate 	 * link-edit.  This option is used when the only input to ld() is a
69*0Sstevel@tonic-gate 	 * mapfile and a 64-bit object is required.  If we've already processed
70*0Sstevel@tonic-gate 	 * a 32-bit object and we find -64, we have an error condition, but let
71*0Sstevel@tonic-gate 	 * this fall through to libld to obtain the default error message.
72*0Sstevel@tonic-gate 	 */
73*0Sstevel@tonic-gate 	opterr = 0;
74*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
75*0Sstevel@tonic-gate 		switch (c) {
76*0Sstevel@tonic-gate 			case '6':
77*0Sstevel@tonic-gate 				return (ELFCLASS64);
78*0Sstevel@tonic-gate 			default:
79*0Sstevel@tonic-gate 				break;
80*0Sstevel@tonic-gate 		}
81*0Sstevel@tonic-gate 	}
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	/*
84*0Sstevel@tonic-gate 	 * Otherwise look for the first ELF object to determine the class of
85*0Sstevel@tonic-gate 	 * objects to operate on.
86*0Sstevel@tonic-gate 	 */
87*0Sstevel@tonic-gate 	for (; optind < argc; optind++) {
88*0Sstevel@tonic-gate 		int		fd;
89*0Sstevel@tonic-gate 		unsigned char	ident[EI_NIDENT];
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 		/*
92*0Sstevel@tonic-gate 		 * If we've already analyzed the initial object, continue.
93*0Sstevel@tonic-gate 		 * We're only interested in skipping all files to check for
94*0Sstevel@tonic-gate 		 * more options, and specifically if the -64 option is set.
95*0Sstevel@tonic-gate 		 */
96*0Sstevel@tonic-gate 		if (class)
97*0Sstevel@tonic-gate 			continue;
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 		/*
100*0Sstevel@tonic-gate 		 * If we detect some more options return to getopt().
101*0Sstevel@tonic-gate 		 * Checking argv[optind][1] against null prevents a forever
102*0Sstevel@tonic-gate 		 * loop if an unadorned `-' argument is passed to us.
103*0Sstevel@tonic-gate 		 */
104*0Sstevel@tonic-gate 		if (argv[optind][0] == '-') {
105*0Sstevel@tonic-gate 			if (argv[optind][1] == '\0')
106*0Sstevel@tonic-gate 				continue;
107*0Sstevel@tonic-gate 			else
108*0Sstevel@tonic-gate 				goto getmore;
109*0Sstevel@tonic-gate 		}
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
112*0Sstevel@tonic-gate 			int err = errno;
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate 			eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_OPEN),
115*0Sstevel@tonic-gate 			    argv[optind], strerror(err));
116*0Sstevel@tonic-gate 			return (0);
117*0Sstevel@tonic-gate 		}
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 		/*
120*0Sstevel@tonic-gate 		 * Determine the files ELF class.
121*0Sstevel@tonic-gate 		 */
122*0Sstevel@tonic-gate 		if ((read(fd, ident, EI_NIDENT) == EI_NIDENT) &&
123*0Sstevel@tonic-gate 		    (ident[EI_MAG0] == ELFMAG0) &&
124*0Sstevel@tonic-gate 		    (ident[EI_MAG1] == ELFMAG1) &&
125*0Sstevel@tonic-gate 		    (ident[EI_MAG2] == ELFMAG2) &&
126*0Sstevel@tonic-gate 		    (ident[EI_MAG3] == ELFMAG3)) {
127*0Sstevel@tonic-gate 			if (((class = ident[EI_CLASS]) != ELFCLASS32) &&
128*0Sstevel@tonic-gate 			    (class != ELFCLASS64))
129*0Sstevel@tonic-gate 				class = 0;
130*0Sstevel@tonic-gate 		}
131*0Sstevel@tonic-gate 		(void) close(fd);
132*0Sstevel@tonic-gate 	}
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 	/*
135*0Sstevel@tonic-gate 	 * If we couldn't establish a class default to 32-bit.
136*0Sstevel@tonic-gate 	 */
137*0Sstevel@tonic-gate 	if (class)
138*0Sstevel@tonic-gate 		return (class);
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	return (ELFCLASS32);
141*0Sstevel@tonic-gate }
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate /*
144*0Sstevel@tonic-gate  * Prepend environment string as a series of options to the argv array.
145*0Sstevel@tonic-gate  */
146*0Sstevel@tonic-gate static int
147*0Sstevel@tonic-gate prepend_ldoptions(char *ld_options, int *argcp, char ***argvp)
148*0Sstevel@tonic-gate {
149*0Sstevel@tonic-gate 	int	nargc;			/* New argc */
150*0Sstevel@tonic-gate 	char	**nargv;			/* New argv */
151*0Sstevel@tonic-gate 	char	*arg, *string;
152*0Sstevel@tonic-gate 	int	count;
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	/*
155*0Sstevel@tonic-gate 	 * Get rid of leading white space, and make sure the string has size.
156*0Sstevel@tonic-gate 	 */
157*0Sstevel@tonic-gate 	while (isspace(*ld_options))
158*0Sstevel@tonic-gate 		ld_options++;
159*0Sstevel@tonic-gate 	if (*ld_options == '\0')
160*0Sstevel@tonic-gate 		return (1);
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	nargc = 0;
163*0Sstevel@tonic-gate 	arg = string = ld_options;
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/*
166*0Sstevel@tonic-gate 	 * Walk the environment string counting any arguments that are
167*0Sstevel@tonic-gate 	 * separated by white space.
168*0Sstevel@tonic-gate 	 */
169*0Sstevel@tonic-gate 	while (*string != '\0') {
170*0Sstevel@tonic-gate 		if (isspace(*string)) {
171*0Sstevel@tonic-gate 			nargc++;
172*0Sstevel@tonic-gate 			while (isspace(*string))
173*0Sstevel@tonic-gate 				string++;
174*0Sstevel@tonic-gate 			arg = string;
175*0Sstevel@tonic-gate 		} else
176*0Sstevel@tonic-gate 			string++;
177*0Sstevel@tonic-gate 	}
178*0Sstevel@tonic-gate 	if (arg != string)
179*0Sstevel@tonic-gate 		nargc++;
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	/*
182*0Sstevel@tonic-gate 	 * Allocate a new argv array big enough to hold the new options from
183*0Sstevel@tonic-gate 	 * the environment string and the old argv options.
184*0Sstevel@tonic-gate 	 */
185*0Sstevel@tonic-gate 	if ((nargv = calloc(nargc + *argcp, sizeof (char *))) == 0)
186*0Sstevel@tonic-gate 		return (0);
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	/*
189*0Sstevel@tonic-gate 	 * Initialize first element of new argv array to be the first element
190*0Sstevel@tonic-gate 	 * of the old argv array (ie. calling programs name).  Then add the new
191*0Sstevel@tonic-gate 	 * args obtained from the environment.
192*0Sstevel@tonic-gate 	 */
193*0Sstevel@tonic-gate 	nargv[0] = (*argvp)[0];
194*0Sstevel@tonic-gate 	nargc = 0;
195*0Sstevel@tonic-gate 	arg = string = ld_options;
196*0Sstevel@tonic-gate 	while (*string != '\0') {
197*0Sstevel@tonic-gate 		if (isspace(*string)) {
198*0Sstevel@tonic-gate 			nargc++;
199*0Sstevel@tonic-gate 			*string++ = '\0';
200*0Sstevel@tonic-gate 			nargv[nargc] = arg;
201*0Sstevel@tonic-gate 			while (isspace(*string))
202*0Sstevel@tonic-gate 				string++;
203*0Sstevel@tonic-gate 			arg = string;
204*0Sstevel@tonic-gate 		} else
205*0Sstevel@tonic-gate 			string++;
206*0Sstevel@tonic-gate 	}
207*0Sstevel@tonic-gate 	if (arg != string) {
208*0Sstevel@tonic-gate 		nargc++;
209*0Sstevel@tonic-gate 		nargv[nargc] = arg;
210*0Sstevel@tonic-gate 	}
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	/*
213*0Sstevel@tonic-gate 	 * Now add the original argv array (skipping argv[0]) to the end of the
214*0Sstevel@tonic-gate 	 * new argv array, and overwrite the old argc and argv.
215*0Sstevel@tonic-gate 	 */
216*0Sstevel@tonic-gate 	for (count = 1; count < *argcp; count++) {
217*0Sstevel@tonic-gate 		nargc++;
218*0Sstevel@tonic-gate 		nargv[nargc] = (*argvp)[count];
219*0Sstevel@tonic-gate 	}
220*0Sstevel@tonic-gate 	*argcp = ++nargc;
221*0Sstevel@tonic-gate 	*argvp = nargv;
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	return (1);
224*0Sstevel@tonic-gate }
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate /*
227*0Sstevel@tonic-gate  * The ld_altexec() function checks to see if there is
228*0Sstevel@tonic-gate  * a LD_ALTEXEC=<path to alternate ld> in the environment.
229*0Sstevel@tonic-gate  * If there is - it will null that variable out - and then
230*0Sstevel@tonic-gate  * exec() the binary pointed to with the same arguements
231*0Sstevel@tonic-gate  * as the originating process.
232*0Sstevel@tonic-gate  * This permits using alternate link-editors (debugging/developer
233*0Sstevel@tonic-gate  * copies) even in complex build environments.
234*0Sstevel@tonic-gate  *
235*0Sstevel@tonic-gate  * If LD_ALTEXEC= isn't set, or the exec() fails this
236*0Sstevel@tonic-gate  * function silently returns and the execution of this
237*0Sstevel@tonic-gate  * link-editor continues on.
238*0Sstevel@tonic-gate  */
239*0Sstevel@tonic-gate void
240*0Sstevel@tonic-gate ld_altexec(char **argv, char **envp)
241*0Sstevel@tonic-gate {
242*0Sstevel@tonic-gate 	char	*execstr;
243*0Sstevel@tonic-gate 	char	**str;
244*0Sstevel@tonic-gate 	for (str = envp; *str; str++) {
245*0Sstevel@tonic-gate 		if (strncmp(*str, MSG_ORIG(MSG_LD_ALTEXEC),
246*0Sstevel@tonic-gate 		    MSG_LD_ALTEXEC_SIZE) == 0) {
247*0Sstevel@tonic-gate 			break;
248*0Sstevel@tonic-gate 		}
249*0Sstevel@tonic-gate 	}
250*0Sstevel@tonic-gate 	if (*str == 0)
251*0Sstevel@tonic-gate 		return;
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	/*
254*0Sstevel@tonic-gate 	 * get a pointer to the actual string - if it's
255*0Sstevel@tonic-gate 	 * a null entry - we return.
256*0Sstevel@tonic-gate 	 */
257*0Sstevel@tonic-gate 	execstr = strdup(*str + MSG_LD_ALTEXEC_SIZE);
258*0Sstevel@tonic-gate 	if (*execstr == '\0')
259*0Sstevel@tonic-gate 		return;
260*0Sstevel@tonic-gate 	/*
261*0Sstevel@tonic-gate 	 * Null out the LD_ALTEXEC= environment entry.
262*0Sstevel@tonic-gate 	 */
263*0Sstevel@tonic-gate 	(*str)[MSG_LD_ALTEXEC_SIZE] = '\0';
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	/*
266*0Sstevel@tonic-gate 	 * Set argv[0] to point to our new linker
267*0Sstevel@tonic-gate 	 */
268*0Sstevel@tonic-gate 	argv[0] = execstr;
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	/*
271*0Sstevel@tonic-gate 	 * And attempt to execute it.
272*0Sstevel@tonic-gate 	 */
273*0Sstevel@tonic-gate 	(void) execve(execstr, argv, envp);
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 	/*
276*0Sstevel@tonic-gate 	 * If the exec failes - we just silently fall
277*0Sstevel@tonic-gate 	 * through and continue execution of the
278*0Sstevel@tonic-gate 	 * current link-editor.
279*0Sstevel@tonic-gate 	 */
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate int
283*0Sstevel@tonic-gate main(int argc, char **argv, char **envp)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate 	char		*ld_options, **oargv = argv;
286*0Sstevel@tonic-gate 	const char	*libld = MSG_ORIG(MSG_LD_LIB32);
287*0Sstevel@tonic-gate 	void		*libld_h;
288*0Sstevel@tonic-gate 	int		(*libld_main)(int, char **);
289*0Sstevel@tonic-gate 	unsigned char	class;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	/*
292*0Sstevel@tonic-gate 	 * XX64 -- Strip "-Wl," from the head of each argument.
293*0Sstevel@tonic-gate 	 * This is to accommodate awkwardness in pasing ld arguments
294*0Sstevel@tonic-gate 	 * to gcc while maintaining the structure of the build
295*0Sstevel@tonic-gate 	 * environment's Makefiles.
296*0Sstevel@tonic-gate 	 */
297*0Sstevel@tonic-gate 	{
298*0Sstevel@tonic-gate 		int i;
299*0Sstevel@tonic-gate 		char *p;
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 		for (i = 0; i < argc; i++) {
302*0Sstevel@tonic-gate 			p = argv[i];
303*0Sstevel@tonic-gate 			while (*(p + 1) == 'W' && strncmp(p, "-Wl,-", 5) == 0)
304*0Sstevel@tonic-gate 				argv[i] = (p += 4);
305*0Sstevel@tonic-gate 		}
306*0Sstevel@tonic-gate 	}
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	/*
309*0Sstevel@tonic-gate 	 * Establish locale.
310*0Sstevel@tonic-gate 	 */
311*0Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
312*0Sstevel@tonic-gate 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	/*
315*0Sstevel@tonic-gate 	 * Execute alternate linker if LD_ALTEXEC environment variable is set.
316*0Sstevel@tonic-gate 	 */
317*0Sstevel@tonic-gate 	ld_altexec(argv, envp);
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 	/*
320*0Sstevel@tonic-gate 	 * Check the LD_OPTIONS environment variable, and if present prepend
321*0Sstevel@tonic-gate 	 * the arguments specified to the command line argument list.
322*0Sstevel@tonic-gate 	 */
323*0Sstevel@tonic-gate 	if ((ld_options = getenv(MSG_ORIG(MSG_LD_OPTIONS))) != NULL) {
324*0Sstevel@tonic-gate 		/*
325*0Sstevel@tonic-gate 		 * Prevent modification of actual environment strings.
326*0Sstevel@tonic-gate 		 */
327*0Sstevel@tonic-gate 		if (((ld_options = strdup(ld_options)) == NULL) ||
328*0Sstevel@tonic-gate 		    (prepend_ldoptions(ld_options, &argc, &argv) == 0))
329*0Sstevel@tonic-gate 			return (1);
330*0Sstevel@tonic-gate 	}
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	/*
333*0Sstevel@tonic-gate 	 * Locate the first input file and from it determine the class of
334*0Sstevel@tonic-gate 	 * objects we're going to process.  If the class is ELFCLASS64 we'll
335*0Sstevel@tonic-gate 	 * specifically load libld.so.3, otherwise we'll fall back to
336*0Sstevel@tonic-gate 	 * libld.so.2.  Note that if the option -64 is encountered a 64-bit
337*0Sstevel@tonic-gate 	 * link is explicitly being requested.
338*0Sstevel@tonic-gate 	 */
339*0Sstevel@tonic-gate 	if ((class = determine_class(argc, argv)) == 0)
340*0Sstevel@tonic-gate 		return (1);
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	/*
343*0Sstevel@tonic-gate 	 * dlopen() right libld implementation.  Note: the RTLD_GLOBAL flag is
344*0Sstevel@tonic-gate 	 * added to make ld behave as if libld was one of its dependencies.
345*0Sstevel@tonic-gate 	 * Support libraries, like libldstab.so.1, may expect this, to get at
346*0Sstevel@tonic-gate 	 * libld_malloc, which they argueably shouldn't be using anyway.
347*0Sstevel@tonic-gate 	 */
348*0Sstevel@tonic-gate 	if (class == ELFCLASS64) {
349*0Sstevel@tonic-gate 		/*
350*0Sstevel@tonic-gate 		 * If we're on a 64-bit kernel, try to exec a full 64-bit
351*0Sstevel@tonic-gate 		 * version of ld.
352*0Sstevel@tonic-gate 		 */
353*0Sstevel@tonic-gate 		conv_check_native(oargv, envp);
354*0Sstevel@tonic-gate 		libld = MSG_ORIG(MSG_LD_LIB64);
355*0Sstevel@tonic-gate 	}
356*0Sstevel@tonic-gate 	if ((libld_h = dlopen(libld, (RTLD_LAZY | RTLD_GLOBAL))) == NULL) {
357*0Sstevel@tonic-gate 		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_DLOPEN), libld, dlerror());
358*0Sstevel@tonic-gate 		return (1);
359*0Sstevel@tonic-gate 	}
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	/*
362*0Sstevel@tonic-gate 	 * Find ld_main(), which is ld's generic entry point.
363*0Sstevel@tonic-gate 	 */
364*0Sstevel@tonic-gate 	if ((libld_main = (int (*)(int, char **))dlsym(libld_h,
365*0Sstevel@tonic-gate 	    MSG_ORIG(MSG_LD_MAIN))) == NULL) {
366*0Sstevel@tonic-gate 		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_DLSYM), libld, dlerror());
367*0Sstevel@tonic-gate 		return (1);
368*0Sstevel@tonic-gate 	}
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 	/*
371*0Sstevel@tonic-gate 	 * Reset the arg counter and getopt(3c) error message flag and call the
372*0Sstevel@tonic-gate 	 * generic entry point.
373*0Sstevel@tonic-gate 	 */
374*0Sstevel@tonic-gate 	optind = opterr = 1;
375*0Sstevel@tonic-gate 	return (libld_main(argc, argv));
376*0Sstevel@tonic-gate }
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate /*
380*0Sstevel@tonic-gate  * Exported interfaces required by our dependencies.  libld and friends bind to
381*0Sstevel@tonic-gate  * the different implementations of these provided by either ld or ld.so.1.
382*0Sstevel@tonic-gate  */
383*0Sstevel@tonic-gate const char *
384*0Sstevel@tonic-gate _ld_msg(Msg mid)
385*0Sstevel@tonic-gate {
386*0Sstevel@tonic-gate 	return (gettext(MSG_ORIG(mid)));
387*0Sstevel@tonic-gate }
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate /*
390*0Sstevel@tonic-gate  * Print a message to stdout
391*0Sstevel@tonic-gate  */
392*0Sstevel@tonic-gate /* VARARGS2 */
393*0Sstevel@tonic-gate void
394*0Sstevel@tonic-gate eprintf(Error error, const char *format, ...)
395*0Sstevel@tonic-gate {
396*0Sstevel@tonic-gate 	va_list			args;
397*0Sstevel@tonic-gate 	static const char	*strings[ERR_NUM] = { MSG_ORIG(MSG_STR_EMPTY) };
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	if (error > ERR_NONE) {
400*0Sstevel@tonic-gate 		if (error == ERR_WARNING) {
401*0Sstevel@tonic-gate 			if (strings[ERR_WARNING] == 0)
402*0Sstevel@tonic-gate 			    strings[ERR_WARNING] = MSG_INTL(MSG_ERR_WARNING);
403*0Sstevel@tonic-gate 		} else if (error == ERR_FATAL) {
404*0Sstevel@tonic-gate 			if (strings[ERR_FATAL] == 0)
405*0Sstevel@tonic-gate 			    strings[ERR_FATAL] = MSG_INTL(MSG_ERR_FATAL);
406*0Sstevel@tonic-gate 		} else if (error == ERR_ELF) {
407*0Sstevel@tonic-gate 			if (strings[ERR_ELF] == 0)
408*0Sstevel@tonic-gate 			    strings[ERR_ELF] = MSG_INTL(MSG_ERR_ELF);
409*0Sstevel@tonic-gate 		}
410*0Sstevel@tonic-gate 		(void) fputs(MSG_ORIG(MSG_STR_LDDIAG), stderr);
411*0Sstevel@tonic-gate 	}
412*0Sstevel@tonic-gate 	(void) fputs(strings[error], stderr);
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	va_start(args, format);
415*0Sstevel@tonic-gate 	(void) vfprintf(stderr, format, args);
416*0Sstevel@tonic-gate 	if (error == ERR_ELF) {
417*0Sstevel@tonic-gate 		int	elferr;
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate 		if ((elferr = elf_errno()) != 0)
420*0Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_ORIG(MSG_STR_ELFDIAG),
421*0Sstevel@tonic-gate 			    elf_errmsg(elferr));
422*0Sstevel@tonic-gate 	}
423*0Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_ORIG(MSG_STR_NL));
424*0Sstevel@tonic-gate 	(void) fflush(stderr);
425*0Sstevel@tonic-gate 	va_end(args);
426*0Sstevel@tonic-gate }
427