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 5*1618Srie * Common Development and Distribution License (the "License"). 6*1618Srie * 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 */ 21*1618Srie 220Sstevel@tonic-gate /* 23*1618Srie * 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 51*1618Srie /* 52*1618Srie * Print a message to stdout 53*1618Srie */ 54*1618Srie /* VARARGS3 */ 55*1618Srie void 56*1618Srie eprintf(Lm_list *lml, Error error, const char *format, ...) 57*1618Srie { 58*1618Srie va_list args; 59*1618Srie static const char *strings[ERR_NUM] = { MSG_ORIG(MSG_STR_EMPTY) }; 60*1618Srie 61*1618Srie #if defined(lint) 62*1618Srie /* 63*1618Srie * The lml argument is only meaningful for diagnostics sent to ld.so.1. 64*1618Srie * Supress the lint error by making a dummy assignment. 65*1618Srie */ 66*1618Srie lml = 0; 67*1618Srie #endif 68*1618Srie if (error > ERR_NONE) { 69*1618Srie if (error == ERR_WARNING) { 70*1618Srie if (strings[ERR_WARNING] == 0) 71*1618Srie strings[ERR_WARNING] = MSG_INTL(MSG_ERR_WARNING); 72*1618Srie } else if (error == ERR_FATAL) { 73*1618Srie if (strings[ERR_FATAL] == 0) 74*1618Srie strings[ERR_FATAL] = MSG_INTL(MSG_ERR_FATAL); 75*1618Srie } else if (error == ERR_ELF) { 76*1618Srie if (strings[ERR_ELF] == 0) 77*1618Srie strings[ERR_ELF] = MSG_INTL(MSG_ERR_ELF); 78*1618Srie } 79*1618Srie (void) fputs(MSG_ORIG(MSG_STR_LDDIAG), stderr); 80*1618Srie } 81*1618Srie (void) fputs(strings[error], stderr); 82*1618Srie 83*1618Srie va_start(args, format); 84*1618Srie (void) vfprintf(stderr, format, args); 85*1618Srie if (error == ERR_ELF) { 86*1618Srie int elferr; 87*1618Srie 88*1618Srie if ((elferr = elf_errno()) != 0) 89*1618Srie (void) fprintf(stderr, MSG_ORIG(MSG_STR_ELFDIAG), 90*1618Srie elf_errmsg(elferr)); 91*1618Srie } 92*1618Srie (void) fprintf(stderr, MSG_ORIG(MSG_STR_NL)); 93*1618Srie (void) fflush(stderr); 94*1618Srie va_end(args); 95*1618Srie } 96*1618Srie 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 1020Sstevel@tonic-gate determine_class(int argc, char ** argv) 1030Sstevel@tonic-gate { 1040Sstevel@tonic-gate unsigned char class = 0; 1050Sstevel@tonic-gate int c; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate getmore: 1080Sstevel@tonic-gate /* 1090Sstevel@tonic-gate * Skip options. 1100Sstevel@tonic-gate * 1110Sstevel@tonic-gate * The only option we're interested in is -64, which enforces a 64-bit 1120Sstevel@tonic-gate * link-edit. This option is used when the only input to ld() is a 1130Sstevel@tonic-gate * mapfile and a 64-bit object is required. If we've already processed 1140Sstevel@tonic-gate * a 32-bit object and we find -64, we have an error condition, but let 1150Sstevel@tonic-gate * this fall through to libld to obtain the default error message. 1160Sstevel@tonic-gate */ 1170Sstevel@tonic-gate opterr = 0; 1180Sstevel@tonic-gate while ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) { 1190Sstevel@tonic-gate switch (c) { 1200Sstevel@tonic-gate case '6': 1210Sstevel@tonic-gate return (ELFCLASS64); 1220Sstevel@tonic-gate default: 1230Sstevel@tonic-gate break; 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate } 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* 1280Sstevel@tonic-gate * Otherwise look for the first ELF object to determine the class of 1290Sstevel@tonic-gate * objects to operate on. 1300Sstevel@tonic-gate */ 1310Sstevel@tonic-gate for (; optind < argc; optind++) { 1320Sstevel@tonic-gate int fd; 1330Sstevel@tonic-gate unsigned char ident[EI_NIDENT]; 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate /* 1360Sstevel@tonic-gate * If we've already analyzed the initial object, continue. 1370Sstevel@tonic-gate * We're only interested in skipping all files to check for 1380Sstevel@tonic-gate * more options, and specifically if the -64 option is set. 1390Sstevel@tonic-gate */ 1400Sstevel@tonic-gate if (class) 1410Sstevel@tonic-gate continue; 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate /* 1440Sstevel@tonic-gate * If we detect some more options return to getopt(). 1450Sstevel@tonic-gate * Checking argv[optind][1] against null prevents a forever 1460Sstevel@tonic-gate * loop if an unadorned `-' argument is passed to us. 1470Sstevel@tonic-gate */ 1480Sstevel@tonic-gate if (argv[optind][0] == '-') { 1490Sstevel@tonic-gate if (argv[optind][1] == '\0') 1500Sstevel@tonic-gate continue; 1510Sstevel@tonic-gate else 1520Sstevel@tonic-gate goto getmore; 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate if ((fd = open(argv[optind], O_RDONLY)) == -1) { 1560Sstevel@tonic-gate int err = errno; 1570Sstevel@tonic-gate 158*1618Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 1590Sstevel@tonic-gate argv[optind], strerror(err)); 1600Sstevel@tonic-gate return (0); 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate /* 1640Sstevel@tonic-gate * Determine the files ELF class. 1650Sstevel@tonic-gate */ 1660Sstevel@tonic-gate if ((read(fd, ident, EI_NIDENT) == EI_NIDENT) && 1670Sstevel@tonic-gate (ident[EI_MAG0] == ELFMAG0) && 1680Sstevel@tonic-gate (ident[EI_MAG1] == ELFMAG1) && 1690Sstevel@tonic-gate (ident[EI_MAG2] == ELFMAG2) && 1700Sstevel@tonic-gate (ident[EI_MAG3] == ELFMAG3)) { 1710Sstevel@tonic-gate if (((class = ident[EI_CLASS]) != ELFCLASS32) && 1720Sstevel@tonic-gate (class != ELFCLASS64)) 1730Sstevel@tonic-gate class = 0; 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate (void) close(fd); 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate /* 1790Sstevel@tonic-gate * If we couldn't establish a class default to 32-bit. 1800Sstevel@tonic-gate */ 1810Sstevel@tonic-gate if (class) 1820Sstevel@tonic-gate return (class); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate return (ELFCLASS32); 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate /* 1880Sstevel@tonic-gate * Prepend environment string as a series of options to the argv array. 1890Sstevel@tonic-gate */ 1900Sstevel@tonic-gate static int 1910Sstevel@tonic-gate prepend_ldoptions(char *ld_options, int *argcp, char ***argvp) 1920Sstevel@tonic-gate { 193*1618Srie int nargc; /* new argc */ 194*1618Srie char **nargv; /* new argv */ 1950Sstevel@tonic-gate char *arg, *string; 1960Sstevel@tonic-gate int count; 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate /* 1990Sstevel@tonic-gate * Get rid of leading white space, and make sure the string has size. 2000Sstevel@tonic-gate */ 2010Sstevel@tonic-gate while (isspace(*ld_options)) 2020Sstevel@tonic-gate ld_options++; 2030Sstevel@tonic-gate if (*ld_options == '\0') 2040Sstevel@tonic-gate return (1); 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate nargc = 0; 2070Sstevel@tonic-gate arg = string = ld_options; 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate /* 2100Sstevel@tonic-gate * Walk the environment string counting any arguments that are 2110Sstevel@tonic-gate * separated by white space. 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate while (*string != '\0') { 2140Sstevel@tonic-gate if (isspace(*string)) { 2150Sstevel@tonic-gate nargc++; 2160Sstevel@tonic-gate while (isspace(*string)) 2170Sstevel@tonic-gate string++; 2180Sstevel@tonic-gate arg = string; 2190Sstevel@tonic-gate } else 2200Sstevel@tonic-gate string++; 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate if (arg != string) 2230Sstevel@tonic-gate nargc++; 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate /* 2260Sstevel@tonic-gate * Allocate a new argv array big enough to hold the new options from 2270Sstevel@tonic-gate * the environment string and the old argv options. 2280Sstevel@tonic-gate */ 229*1618Srie if ((nargv = calloc(nargc + *argcp, sizeof (char *))) == 0) { 230*1618Srie int err = errno; 231*1618Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_ALLOC), strerror(err)); 2320Sstevel@tonic-gate return (0); 233*1618Srie } 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate /* 2360Sstevel@tonic-gate * Initialize first element of new argv array to be the first element 2370Sstevel@tonic-gate * of the old argv array (ie. calling programs name). Then add the new 2380Sstevel@tonic-gate * args obtained from the environment. 2390Sstevel@tonic-gate */ 2400Sstevel@tonic-gate nargv[0] = (*argvp)[0]; 2410Sstevel@tonic-gate nargc = 0; 2420Sstevel@tonic-gate arg = string = ld_options; 2430Sstevel@tonic-gate while (*string != '\0') { 2440Sstevel@tonic-gate if (isspace(*string)) { 2450Sstevel@tonic-gate nargc++; 2460Sstevel@tonic-gate *string++ = '\0'; 2470Sstevel@tonic-gate nargv[nargc] = arg; 2480Sstevel@tonic-gate while (isspace(*string)) 2490Sstevel@tonic-gate string++; 2500Sstevel@tonic-gate arg = string; 2510Sstevel@tonic-gate } else 2520Sstevel@tonic-gate string++; 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate if (arg != string) { 2550Sstevel@tonic-gate nargc++; 2560Sstevel@tonic-gate nargv[nargc] = arg; 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate /* 2600Sstevel@tonic-gate * Now add the original argv array (skipping argv[0]) to the end of the 2610Sstevel@tonic-gate * new argv array, and overwrite the old argc and argv. 2620Sstevel@tonic-gate */ 2630Sstevel@tonic-gate for (count = 1; count < *argcp; count++) { 2640Sstevel@tonic-gate nargc++; 2650Sstevel@tonic-gate nargv[nargc] = (*argvp)[count]; 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate *argcp = ++nargc; 2680Sstevel@tonic-gate *argvp = nargv; 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate return (1); 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* 274*1618Srie * Check to see if there is a LD_ALTEXEC=<path to alternate ld> in the 275*1618Srie * environment. If so, first null the environment variable out, and then 276*1618Srie * exec() the binary pointed to by the environment variable, passing the same 277*1618Srie * arguments as the originating process. This mechanism permits using 278*1618Srie * alternate link-editors (debugging/developer copies) even in complex build 279*1618Srie * environments. 2800Sstevel@tonic-gate * 281*1618Srie * If LD_ALTEXEC= isn't set, or the exec() fails, silently return and allow the 282*1618Srie * current link-editor to execute. 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gate void 2850Sstevel@tonic-gate ld_altexec(char **argv, char **envp) 2860Sstevel@tonic-gate { 2870Sstevel@tonic-gate char *execstr; 2880Sstevel@tonic-gate char **str; 2890Sstevel@tonic-gate for (str = envp; *str; str++) { 2900Sstevel@tonic-gate if (strncmp(*str, MSG_ORIG(MSG_LD_ALTEXEC), 2910Sstevel@tonic-gate MSG_LD_ALTEXEC_SIZE) == 0) { 2920Sstevel@tonic-gate break; 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate if (*str == 0) 2960Sstevel@tonic-gate return; 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate /* 2990Sstevel@tonic-gate * get a pointer to the actual string - if it's 3000Sstevel@tonic-gate * a null entry - we return. 3010Sstevel@tonic-gate */ 3020Sstevel@tonic-gate execstr = strdup(*str + MSG_LD_ALTEXEC_SIZE); 3030Sstevel@tonic-gate if (*execstr == '\0') 3040Sstevel@tonic-gate return; 3050Sstevel@tonic-gate /* 3060Sstevel@tonic-gate * Null out the LD_ALTEXEC= environment entry. 3070Sstevel@tonic-gate */ 3080Sstevel@tonic-gate (*str)[MSG_LD_ALTEXEC_SIZE] = '\0'; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate /* 3110Sstevel@tonic-gate * Set argv[0] to point to our new linker 3120Sstevel@tonic-gate */ 3130Sstevel@tonic-gate argv[0] = execstr; 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate /* 3160Sstevel@tonic-gate * And attempt to execute it. 3170Sstevel@tonic-gate */ 3180Sstevel@tonic-gate (void) execve(execstr, argv, envp); 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate /* 321*1618Srie * If the exec() fails, silently fall through and continue execution of 322*1618Srie * the current link-editor. 3230Sstevel@tonic-gate */ 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate int 3270Sstevel@tonic-gate main(int argc, char **argv, char **envp) 3280Sstevel@tonic-gate { 3290Sstevel@tonic-gate char *ld_options, **oargv = argv; 330*1618Srie uchar_t class; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* 333*1618Srie * XX64 -- Strip "-Wl," from the head of each argument. This is to 334*1618Srie * accommodate awkwardness in passing ld arguments to gcc while 335*1618Srie * maintaining the structure of the OSNet build environment's Makefiles. 3360Sstevel@tonic-gate */ 3370Sstevel@tonic-gate { 3380Sstevel@tonic-gate int i; 3390Sstevel@tonic-gate char *p; 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate for (i = 0; i < argc; i++) { 3420Sstevel@tonic-gate p = argv[i]; 3430Sstevel@tonic-gate while (*(p + 1) == 'W' && strncmp(p, "-Wl,-", 5) == 0) 3440Sstevel@tonic-gate argv[i] = (p += 4); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate /* 3490Sstevel@tonic-gate * Establish locale. 3500Sstevel@tonic-gate */ 3510Sstevel@tonic-gate (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 3520Sstevel@tonic-gate (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * Execute alternate linker if LD_ALTEXEC environment variable is set. 3560Sstevel@tonic-gate */ 3570Sstevel@tonic-gate ld_altexec(argv, envp); 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate /* 3600Sstevel@tonic-gate * Check the LD_OPTIONS environment variable, and if present prepend 3610Sstevel@tonic-gate * the arguments specified to the command line argument list. 3620Sstevel@tonic-gate */ 3630Sstevel@tonic-gate if ((ld_options = getenv(MSG_ORIG(MSG_LD_OPTIONS))) != NULL) { 3640Sstevel@tonic-gate /* 3650Sstevel@tonic-gate * Prevent modification of actual environment strings. 3660Sstevel@tonic-gate */ 3670Sstevel@tonic-gate if (((ld_options = strdup(ld_options)) == NULL) || 3680Sstevel@tonic-gate (prepend_ldoptions(ld_options, &argc, &argv) == 0)) 3690Sstevel@tonic-gate return (1); 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate /* 373*1618Srie * Locate the first input file and from this file determine the class of 3740Sstevel@tonic-gate * objects we're going to process. If the class is ELFCLASS64 we'll 375*1618Srie * call the ELF64 class of interfaces, else the ELF32 class. Note that 376*1618Srie * if the option -64 is encountered a 64-bit link is explicitly being 377*1618Srie * requested. 3780Sstevel@tonic-gate */ 3790Sstevel@tonic-gate if ((class = determine_class(argc, argv)) == 0) 3800Sstevel@tonic-gate return (1); 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate /* 383*1618Srie * If we're on a 64-bit kernel, try to exec a full 64-bit version of ld. 3840Sstevel@tonic-gate */ 385*1618Srie if (class == ELFCLASS64) 3860Sstevel@tonic-gate conv_check_native(oargv, envp); 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate /* 389*1618Srie * Reset the getopt(3c) error message flag, and call the generic entry 390*1618Srie * point using the appropriate class. 3910Sstevel@tonic-gate */ 3920Sstevel@tonic-gate optind = opterr = 1; 393*1618Srie if (class == ELFCLASS64) 394*1618Srie return (ld64_main(argc, argv)); 395*1618Srie else 396*1618Srie return (ld32_main(argc, argv)); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate /* 4000Sstevel@tonic-gate * Exported interfaces required by our dependencies. libld and friends bind to 4010Sstevel@tonic-gate * the different implementations of these provided by either ld or ld.so.1. 4020Sstevel@tonic-gate */ 4030Sstevel@tonic-gate const char * 4040Sstevel@tonic-gate _ld_msg(Msg mid) 4050Sstevel@tonic-gate { 4060Sstevel@tonic-gate return (gettext(MSG_ORIG(mid))); 4070Sstevel@tonic-gate } 408