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