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