10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51618Srie * Common Development and Distribution License (the "License"). 61618Srie * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211618Srie 220Sstevel@tonic-gate /* 231618Srie * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <stdio.h> 300Sstevel@tonic-gate #include <stdlib.h> 310Sstevel@tonic-gate #include <unistd.h> 320Sstevel@tonic-gate #include <stdarg.h> 330Sstevel@tonic-gate #include <string.h> 340Sstevel@tonic-gate #include <errno.h> 350Sstevel@tonic-gate #include <fcntl.h> 360Sstevel@tonic-gate #include <libintl.h> 370Sstevel@tonic-gate #include <locale.h> 380Sstevel@tonic-gate #include <fcntl.h> 390Sstevel@tonic-gate #include "conv.h" 400Sstevel@tonic-gate #include "libld.h" 410Sstevel@tonic-gate #include "msg.h" 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* 440Sstevel@tonic-gate * The following prevent us from having to include ctype.h which defines these 450Sstevel@tonic-gate * functions as macros which reference the __ctype[] array. Go through .plt's 460Sstevel@tonic-gate * to get to these functions in libc rather than have every invocation of ld 470Sstevel@tonic-gate * have to suffer the R_SPARC_COPY overhead of the __ctype[] array. 480Sstevel@tonic-gate */ 490Sstevel@tonic-gate extern int isspace(int); 500Sstevel@tonic-gate 511618Srie /* 521618Srie * Print a message to stdout 531618Srie */ 541618Srie /* VARARGS3 */ 551618Srie void 561618Srie eprintf(Lm_list *lml, Error error, const char *format, ...) 571618Srie { 581618Srie va_list args; 591618Srie static const char *strings[ERR_NUM] = { MSG_ORIG(MSG_STR_EMPTY) }; 601618Srie 611618Srie #if defined(lint) 621618Srie /* 631618Srie * The lml argument is only meaningful for diagnostics sent to ld.so.1. 641618Srie * Supress the lint error by making a dummy assignment. 651618Srie */ 661618Srie lml = 0; 671618Srie #endif 681618Srie if (error > ERR_NONE) { 691618Srie if (error == ERR_WARNING) { 701618Srie if (strings[ERR_WARNING] == 0) 711618Srie strings[ERR_WARNING] = MSG_INTL(MSG_ERR_WARNING); 721618Srie } else if (error == ERR_FATAL) { 731618Srie if (strings[ERR_FATAL] == 0) 741618Srie strings[ERR_FATAL] = MSG_INTL(MSG_ERR_FATAL); 751618Srie } else if (error == ERR_ELF) { 761618Srie if (strings[ERR_ELF] == 0) 771618Srie strings[ERR_ELF] = MSG_INTL(MSG_ERR_ELF); 781618Srie } 791618Srie (void) fputs(MSG_ORIG(MSG_STR_LDDIAG), stderr); 801618Srie } 811618Srie (void) fputs(strings[error], stderr); 821618Srie 831618Srie va_start(args, format); 841618Srie (void) vfprintf(stderr, format, args); 851618Srie if (error == ERR_ELF) { 861618Srie int elferr; 871618Srie 881618Srie if ((elferr = elf_errno()) != 0) 891618Srie (void) fprintf(stderr, MSG_ORIG(MSG_STR_ELFDIAG), 901618Srie elf_errmsg(elferr)); 911618Srie } 921618Srie (void) fprintf(stderr, MSG_ORIG(MSG_STR_NL)); 931618Srie (void) fflush(stderr); 941618Srie va_end(args); 951618Srie } 961618Srie 970Sstevel@tonic-gate 980Sstevel@tonic-gate /* 990Sstevel@tonic-gate * Determine whether we need the Elf32 or Elf64 libld. 1000Sstevel@tonic-gate */ 1010Sstevel@tonic-gate static int 102*2647Srie determine_class(int argc, char **argv, uchar_t *aoutclass, uchar_t *ldclass) 1030Sstevel@tonic-gate { 104*2647Srie #if defined(__sparcv9) || defined(__amd64) 105*2647Srie uchar_t aclass = 0, lclass = ELFCLASS64; 106*2647Srie #else 107*2647Srie uchar_t aclass = 0, lclass = 0; 108*2647Srie #endif 109*2647Srie int c; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate getmore: 1120Sstevel@tonic-gate /* 1130Sstevel@tonic-gate * Skip options. 1140Sstevel@tonic-gate * 115*2647Srie * The only options we're interested in is -64 or -altzexec64. The -64 116*2647Srie * option is used when the only input to ld() is a mapfile or archive, 117*2647Srie * and a 64-bit a.out is required. The -zaltexec64 option requests the 118*2647Srie * 64-bit version of ld() is used regardless of the required a.out. 119*2647Srie * 120*2647Srie * If we've already processed a 32-bit object and we find -64, we have 121*2647Srie * an error condition, but let this fall through to libld to obtain the 122*2647Srie * default error message. 1230Sstevel@tonic-gate */ 1240Sstevel@tonic-gate opterr = 0; 1250Sstevel@tonic-gate while ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) { 1260Sstevel@tonic-gate switch (c) { 1270Sstevel@tonic-gate case '6': 128*2647Srie if (strncmp(optarg, MSG_ORIG(MSG_ARG_FOUR), 129*2647Srie MSG_ARG_FOUR_SIZE) == 0) 130*2647Srie aclass = ELFCLASS64; 131*2647Srie break; 132*2647Srie #if !defined(__sparcv9) && !defined(__amd64) 133*2647Srie case 'z': 134*2647Srie if (strncmp(optarg, MSG_ORIG(MSG_ARG_ALTEXEC64), 135*2647Srie MSG_ARG_ALTEXEC64_SIZE) == 0) 136*2647Srie lclass = ELFCLASS64; 137*2647Srie break; 138*2647Srie #endif 1390Sstevel@tonic-gate default: 1400Sstevel@tonic-gate break; 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate /* 145*2647Srie * Continue to look for the first ELF object to determine the class of 1460Sstevel@tonic-gate * objects to operate on. 1470Sstevel@tonic-gate */ 1480Sstevel@tonic-gate for (; optind < argc; optind++) { 1490Sstevel@tonic-gate int fd; 1500Sstevel@tonic-gate unsigned char ident[EI_NIDENT]; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate /* 1530Sstevel@tonic-gate * If we detect some more options return to getopt(). 1540Sstevel@tonic-gate * Checking argv[optind][1] against null prevents a forever 1550Sstevel@tonic-gate * loop if an unadorned `-' argument is passed to us. 1560Sstevel@tonic-gate */ 1570Sstevel@tonic-gate if (argv[optind][0] == '-') { 1580Sstevel@tonic-gate if (argv[optind][1] == '\0') 1590Sstevel@tonic-gate continue; 1600Sstevel@tonic-gate else 1610Sstevel@tonic-gate goto getmore; 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate 164*2647Srie /* 165*2647Srie * If we've already determined the object class, continue. 166*2647Srie * We're only interested in skipping all files to check for 167*2647Srie * more options, and specifically if the -64 option is set. 168*2647Srie */ 169*2647Srie if (aclass) 170*2647Srie continue; 171*2647Srie 172*2647Srie /* 173*2647Srie * Open the file and determine the files ELF class. 174*2647Srie */ 1750Sstevel@tonic-gate if ((fd = open(argv[optind], O_RDONLY)) == -1) { 1760Sstevel@tonic-gate int err = errno; 1770Sstevel@tonic-gate 1781618Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 1790Sstevel@tonic-gate argv[optind], strerror(err)); 180*2647Srie return (1); 1810Sstevel@tonic-gate } 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate if ((read(fd, ident, EI_NIDENT) == EI_NIDENT) && 1840Sstevel@tonic-gate (ident[EI_MAG0] == ELFMAG0) && 1850Sstevel@tonic-gate (ident[EI_MAG1] == ELFMAG1) && 1860Sstevel@tonic-gate (ident[EI_MAG2] == ELFMAG2) && 1870Sstevel@tonic-gate (ident[EI_MAG3] == ELFMAG3)) { 188*2647Srie if (((aclass = ident[EI_CLASS]) != ELFCLASS32) && 189*2647Srie (aclass != ELFCLASS64)) 190*2647Srie aclass = 0; 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate (void) close(fd); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate /* 1960Sstevel@tonic-gate * If we couldn't establish a class default to 32-bit. 1970Sstevel@tonic-gate */ 198*2647Srie if (aclass == 0) 199*2647Srie aclass = ELFCLASS32; 200*2647Srie if (lclass == 0) 201*2647Srie lclass = ELFCLASS32; 2020Sstevel@tonic-gate 203*2647Srie *aoutclass = aclass; 204*2647Srie *ldclass = lclass; 205*2647Srie return (0); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* 2090Sstevel@tonic-gate * Prepend environment string as a series of options to the argv array. 2100Sstevel@tonic-gate */ 2110Sstevel@tonic-gate static int 2120Sstevel@tonic-gate prepend_ldoptions(char *ld_options, int *argcp, char ***argvp) 2130Sstevel@tonic-gate { 2141618Srie int nargc; /* new argc */ 2151618Srie char **nargv; /* new argv */ 2160Sstevel@tonic-gate char *arg, *string; 2170Sstevel@tonic-gate int count; 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate /* 2200Sstevel@tonic-gate * Get rid of leading white space, and make sure the string has size. 2210Sstevel@tonic-gate */ 2220Sstevel@tonic-gate while (isspace(*ld_options)) 2230Sstevel@tonic-gate ld_options++; 2240Sstevel@tonic-gate if (*ld_options == '\0') 2250Sstevel@tonic-gate return (1); 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate nargc = 0; 2280Sstevel@tonic-gate arg = string = ld_options; 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* 2310Sstevel@tonic-gate * Walk the environment string counting any arguments that are 2320Sstevel@tonic-gate * separated by white space. 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate while (*string != '\0') { 2350Sstevel@tonic-gate if (isspace(*string)) { 2360Sstevel@tonic-gate nargc++; 2370Sstevel@tonic-gate while (isspace(*string)) 2380Sstevel@tonic-gate string++; 2390Sstevel@tonic-gate arg = string; 2400Sstevel@tonic-gate } else 2410Sstevel@tonic-gate string++; 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate if (arg != string) 2440Sstevel@tonic-gate nargc++; 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate /* 2470Sstevel@tonic-gate * Allocate a new argv array big enough to hold the new options from 2480Sstevel@tonic-gate * the environment string and the old argv options. 2490Sstevel@tonic-gate */ 2501618Srie if ((nargv = calloc(nargc + *argcp, sizeof (char *))) == 0) { 2511618Srie int err = errno; 2521618Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_ALLOC), strerror(err)); 2530Sstevel@tonic-gate return (0); 2541618Srie } 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate /* 2570Sstevel@tonic-gate * Initialize first element of new argv array to be the first element 2580Sstevel@tonic-gate * of the old argv array (ie. calling programs name). Then add the new 2590Sstevel@tonic-gate * args obtained from the environment. 2600Sstevel@tonic-gate */ 2610Sstevel@tonic-gate nargv[0] = (*argvp)[0]; 2620Sstevel@tonic-gate nargc = 0; 2630Sstevel@tonic-gate arg = string = ld_options; 2640Sstevel@tonic-gate while (*string != '\0') { 2650Sstevel@tonic-gate if (isspace(*string)) { 2660Sstevel@tonic-gate nargc++; 2670Sstevel@tonic-gate *string++ = '\0'; 2680Sstevel@tonic-gate nargv[nargc] = arg; 2690Sstevel@tonic-gate while (isspace(*string)) 2700Sstevel@tonic-gate string++; 2710Sstevel@tonic-gate arg = string; 2720Sstevel@tonic-gate } else 2730Sstevel@tonic-gate string++; 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate if (arg != string) { 2760Sstevel@tonic-gate nargc++; 2770Sstevel@tonic-gate nargv[nargc] = arg; 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate /* 2810Sstevel@tonic-gate * Now add the original argv array (skipping argv[0]) to the end of the 2820Sstevel@tonic-gate * new argv array, and overwrite the old argc and argv. 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gate for (count = 1; count < *argcp; count++) { 2850Sstevel@tonic-gate nargc++; 2860Sstevel@tonic-gate nargv[nargc] = (*argvp)[count]; 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate *argcp = ++nargc; 2890Sstevel@tonic-gate *argvp = nargv; 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate return (1); 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate /* 2951618Srie * Check to see if there is a LD_ALTEXEC=<path to alternate ld> in the 2961618Srie * environment. If so, first null the environment variable out, and then 2971618Srie * exec() the binary pointed to by the environment variable, passing the same 2981618Srie * arguments as the originating process. This mechanism permits using 2991618Srie * alternate link-editors (debugging/developer copies) even in complex build 3001618Srie * environments. 3010Sstevel@tonic-gate */ 302*2647Srie static int 3030Sstevel@tonic-gate ld_altexec(char **argv, char **envp) 3040Sstevel@tonic-gate { 3050Sstevel@tonic-gate char *execstr; 3060Sstevel@tonic-gate char **str; 307*2647Srie int err; 308*2647Srie 3090Sstevel@tonic-gate for (str = envp; *str; str++) { 3100Sstevel@tonic-gate if (strncmp(*str, MSG_ORIG(MSG_LD_ALTEXEC), 3110Sstevel@tonic-gate MSG_LD_ALTEXEC_SIZE) == 0) { 3120Sstevel@tonic-gate break; 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate /* 317*2647Srie * If LD_ALTEXEC isn't set, return to continue executing the present 318*2647Srie * link-editor. 319*2647Srie */ 320*2647Srie if (*str == 0) 321*2647Srie return (0); 322*2647Srie 323*2647Srie /* 324*2647Srie * Get a pointer to the actual string. If it's a null entry, return. 3250Sstevel@tonic-gate */ 3260Sstevel@tonic-gate execstr = strdup(*str + MSG_LD_ALTEXEC_SIZE); 3270Sstevel@tonic-gate if (*execstr == '\0') 328*2647Srie return (0); 329*2647Srie 3300Sstevel@tonic-gate /* 3310Sstevel@tonic-gate * Null out the LD_ALTEXEC= environment entry. 3320Sstevel@tonic-gate */ 3330Sstevel@tonic-gate (*str)[MSG_LD_ALTEXEC_SIZE] = '\0'; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate /* 3360Sstevel@tonic-gate * Set argv[0] to point to our new linker 3370Sstevel@tonic-gate */ 3380Sstevel@tonic-gate argv[0] = execstr; 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate /* 3410Sstevel@tonic-gate * And attempt to execute it. 3420Sstevel@tonic-gate */ 3430Sstevel@tonic-gate (void) execve(execstr, argv, envp); 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate /* 346*2647Srie * If the exec() fails, return a failure indication. 3470Sstevel@tonic-gate */ 348*2647Srie err = errno; 349*2647Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_EXEC), execstr, 350*2647Srie strerror(err)); 351*2647Srie return (1); 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate int 3550Sstevel@tonic-gate main(int argc, char **argv, char **envp) 3560Sstevel@tonic-gate { 3570Sstevel@tonic-gate char *ld_options, **oargv = argv; 358*2647Srie uchar_t aoutclass, ldclass, checkclass; 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* 3611618Srie * XX64 -- Strip "-Wl," from the head of each argument. This is to 3621618Srie * accommodate awkwardness in passing ld arguments to gcc while 3631618Srie * maintaining the structure of the OSNet build environment's Makefiles. 3640Sstevel@tonic-gate */ 3650Sstevel@tonic-gate { 3660Sstevel@tonic-gate int i; 3670Sstevel@tonic-gate char *p; 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate for (i = 0; i < argc; i++) { 3700Sstevel@tonic-gate p = argv[i]; 3710Sstevel@tonic-gate while (*(p + 1) == 'W' && strncmp(p, "-Wl,-", 5) == 0) 3720Sstevel@tonic-gate argv[i] = (p += 4); 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate /* 3770Sstevel@tonic-gate * Establish locale. 3780Sstevel@tonic-gate */ 3790Sstevel@tonic-gate (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 3800Sstevel@tonic-gate (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate /* 383*2647Srie * Execute an alternate linker if the LD_ALTEXEC environment variable is 384*2647Srie * set. If a specified alternative could not be found, bail. 3850Sstevel@tonic-gate */ 386*2647Srie if (ld_altexec(argv, envp)) 387*2647Srie return (1); 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate /* 3900Sstevel@tonic-gate * Check the LD_OPTIONS environment variable, and if present prepend 3910Sstevel@tonic-gate * the arguments specified to the command line argument list. 3920Sstevel@tonic-gate */ 3930Sstevel@tonic-gate if ((ld_options = getenv(MSG_ORIG(MSG_LD_OPTIONS))) != NULL) { 3940Sstevel@tonic-gate /* 3950Sstevel@tonic-gate * Prevent modification of actual environment strings. 3960Sstevel@tonic-gate */ 3970Sstevel@tonic-gate if (((ld_options = strdup(ld_options)) == NULL) || 3980Sstevel@tonic-gate (prepend_ldoptions(ld_options, &argc, &argv) == 0)) 3990Sstevel@tonic-gate return (1); 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate /* 403*2647Srie * Determine the object class, and link-editor class required. 4040Sstevel@tonic-gate */ 405*2647Srie if (determine_class(argc, argv, &aoutclass, &ldclass)) 4060Sstevel@tonic-gate return (1); 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate /* 409*2647Srie * If we're processing 64-bit objects, or the user specifically asked 410*2647Srie * for a 64-bit link-editor, determine if a 64-bit ld() can be executed. 411*2647Srie * Bail if a 64-bit ld() was explicitly asked for, but one could not be 412*2647Srie * found. 4130Sstevel@tonic-gate */ 414*2647Srie if ((aoutclass == ELFCLASS64) || (ldclass == ELFCLASS64)) 415*2647Srie checkclass = conv_check_native(oargv, envp); 416*2647Srie 417*2647Srie if ((ldclass == ELFCLASS64) && (checkclass != ELFCLASS64)) { 418*2647Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_64)); 419*2647Srie return (1); 420*2647Srie } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate /* 4231618Srie * Reset the getopt(3c) error message flag, and call the generic entry 4241618Srie * point using the appropriate class. 4250Sstevel@tonic-gate */ 4260Sstevel@tonic-gate optind = opterr = 1; 427*2647Srie if (aoutclass == ELFCLASS64) 4281618Srie return (ld64_main(argc, argv)); 4291618Srie else 4301618Srie return (ld32_main(argc, argv)); 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate /* 4340Sstevel@tonic-gate * Exported interfaces required by our dependencies. libld and friends bind to 4350Sstevel@tonic-gate * the different implementations of these provided by either ld or ld.so.1. 4360Sstevel@tonic-gate */ 4370Sstevel@tonic-gate const char * 4380Sstevel@tonic-gate _ld_msg(Msg mid) 4390Sstevel@tonic-gate { 4400Sstevel@tonic-gate return (gettext(MSG_ORIG(mid))); 4410Sstevel@tonic-gate } 442