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 /* 239646SAli.Bahrami@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #include <stdio.h> 280Sstevel@tonic-gate #include <stdlib.h> 290Sstevel@tonic-gate #include <unistd.h> 300Sstevel@tonic-gate #include <stdarg.h> 310Sstevel@tonic-gate #include <string.h> 326206Sab196087 #include <strings.h> 330Sstevel@tonic-gate #include <errno.h> 340Sstevel@tonic-gate #include <fcntl.h> 350Sstevel@tonic-gate #include <libintl.h> 360Sstevel@tonic-gate #include <locale.h> 370Sstevel@tonic-gate #include <fcntl.h> 389646SAli.Bahrami@Sun.COM #include <ar.h> 399646SAli.Bahrami@Sun.COM #include <gelf.h> 400Sstevel@tonic-gate #include "conv.h" 410Sstevel@tonic-gate #include "libld.h" 426206Sab196087 #include "machdep.h" 430Sstevel@tonic-gate #include "msg.h" 440Sstevel@tonic-gate 450Sstevel@tonic-gate /* 460Sstevel@tonic-gate * The following prevent us from having to include ctype.h which defines these 470Sstevel@tonic-gate * functions as macros which reference the __ctype[] array. Go through .plt's 480Sstevel@tonic-gate * to get to these functions in libc rather than have every invocation of ld 490Sstevel@tonic-gate * have to suffer the R_SPARC_COPY overhead of the __ctype[] array. 500Sstevel@tonic-gate */ 510Sstevel@tonic-gate extern int isspace(int); 520Sstevel@tonic-gate 531618Srie /* 549646SAli.Bahrami@Sun.COM * We examine ELF objects, and archives containing ELF objects, in order 559646SAli.Bahrami@Sun.COM * to determine the ELFCLASS of the resulting object and/or the linker to be 569646SAli.Bahrami@Sun.COM * used. We want to avoid the overhead of libelf for this, at least until 579646SAli.Bahrami@Sun.COM * we are certain that we need it, so we start by reading bytes from 589646SAli.Bahrami@Sun.COM * the beginning of the file. This type defines the buffer used to read 599646SAli.Bahrami@Sun.COM * these initial bytes. 609646SAli.Bahrami@Sun.COM * 619646SAli.Bahrami@Sun.COM * A plain ELF object will start with an ELF header, whereas an archive 629646SAli.Bahrami@Sun.COM * starts with a magic string (ARMAG) that is SARMAG bytes long. Any valid 639646SAli.Bahrami@Sun.COM * ELF file or archive will contain more bytes than this buffer, so any 649646SAli.Bahrami@Sun.COM * file shorter than this can be safely assummed not to be of interest. 659646SAli.Bahrami@Sun.COM * 669646SAli.Bahrami@Sun.COM * The ELF header for ELFCLASS32 and ELFCLASS64 are identical up through the 679646SAli.Bahrami@Sun.COM * the e_version field, and all the information we require is found in this 689646SAli.Bahrami@Sun.COM * common prefix. Furthermore, this cannot change, as the layout of an ELF 699646SAli.Bahrami@Sun.COM * header is fixed by the ELF ABI. Hence, the ehdr part of this union is 709646SAli.Bahrami@Sun.COM * not a full ELF header, but only the class-independent prefix that we need. 719646SAli.Bahrami@Sun.COM * 729646SAli.Bahrami@Sun.COM * As this is a raw (non-libelf) read, we are responsible for handling any 739646SAli.Bahrami@Sun.COM * byte order difference between the object and the system running this 749646SAli.Bahrami@Sun.COM * program when we read any datum larger than a byte (i.e. e_machine) from 759646SAli.Bahrami@Sun.COM * this header. 769646SAli.Bahrami@Sun.COM */ 779646SAli.Bahrami@Sun.COM typedef union { 789646SAli.Bahrami@Sun.COM struct { /* Must match start of ELFxx_Ehdr in <sys/elf.h> */ 799646SAli.Bahrami@Sun.COM uchar_t e_ident[EI_NIDENT]; /* ident bytes */ 809646SAli.Bahrami@Sun.COM Half e_type; /* file type */ 819646SAli.Bahrami@Sun.COM Half e_machine; /* target machine */ 829646SAli.Bahrami@Sun.COM } ehdr; 839646SAli.Bahrami@Sun.COM char armag[SARMAG]; 849646SAli.Bahrami@Sun.COM } FILE_HDR; 859646SAli.Bahrami@Sun.COM 869646SAli.Bahrami@Sun.COM 879646SAli.Bahrami@Sun.COM /* 881618Srie * Print a message to stdout 891618Srie */ 901618Srie /* VARARGS3 */ 911618Srie void 921618Srie eprintf(Lm_list *lml, Error error, const char *format, ...) 931618Srie { 941618Srie va_list args; 951618Srie static const char *strings[ERR_NUM] = { MSG_ORIG(MSG_STR_EMPTY) }; 961618Srie 971618Srie #if defined(lint) 981618Srie /* 991618Srie * The lml argument is only meaningful for diagnostics sent to ld.so.1. 1001618Srie * Supress the lint error by making a dummy assignment. 1011618Srie */ 1021618Srie lml = 0; 1031618Srie #endif 1041618Srie if (error > ERR_NONE) { 1051618Srie if (error == ERR_WARNING) { 1061618Srie if (strings[ERR_WARNING] == 0) 1076206Sab196087 strings[ERR_WARNING] = 1086206Sab196087 MSG_INTL(MSG_ERR_WARNING); 1091618Srie } else if (error == ERR_FATAL) { 1101618Srie if (strings[ERR_FATAL] == 0) 1116206Sab196087 strings[ERR_FATAL] = MSG_INTL(MSG_ERR_FATAL); 1121618Srie } else if (error == ERR_ELF) { 1131618Srie if (strings[ERR_ELF] == 0) 1146206Sab196087 strings[ERR_ELF] = MSG_INTL(MSG_ERR_ELF); 1151618Srie } 1161618Srie (void) fputs(MSG_ORIG(MSG_STR_LDDIAG), stderr); 1171618Srie } 1181618Srie (void) fputs(strings[error], stderr); 1191618Srie 1201618Srie va_start(args, format); 1211618Srie (void) vfprintf(stderr, format, args); 1221618Srie if (error == ERR_ELF) { 1231618Srie int elferr; 1241618Srie 1251618Srie if ((elferr = elf_errno()) != 0) 1261618Srie (void) fprintf(stderr, MSG_ORIG(MSG_STR_ELFDIAG), 1271618Srie elf_errmsg(elferr)); 1281618Srie } 1291618Srie (void) fprintf(stderr, MSG_ORIG(MSG_STR_NL)); 1301618Srie (void) fflush(stderr); 1311618Srie va_end(args); 1321618Srie } 1331618Srie 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate /* 1369646SAli.Bahrami@Sun.COM * Examine the first object in an archive to determine its ELFCLASS 1379646SAli.Bahrami@Sun.COM * and machine type. 1389646SAli.Bahrami@Sun.COM * 1399646SAli.Bahrami@Sun.COM * entry: 1409646SAli.Bahrami@Sun.COM * fd - Open file descriptor for file 1419646SAli.Bahrami@Sun.COM * elf - libelf ELF descriptor 1429646SAli.Bahrami@Sun.COM * class_ret, mach_ret - Address of variables to receive ELFCLASS 1439646SAli.Bahrami@Sun.COM * and machine type. 1449646SAli.Bahrami@Sun.COM * 1459646SAli.Bahrami@Sun.COM * exit: 1469646SAli.Bahrami@Sun.COM * On success, *class_ret and *mach_ret are filled in, and True (1) 1479646SAli.Bahrami@Sun.COM * is returned. On failure, False (0) is returned. 1480Sstevel@tonic-gate */ 1490Sstevel@tonic-gate static int 1509646SAli.Bahrami@Sun.COM archive(int fd, Elf *elf, uchar_t *class_ret, Half *mach_ret) 1519646SAli.Bahrami@Sun.COM { 1529646SAli.Bahrami@Sun.COM Elf_Cmd cmd = ELF_C_READ; 1539646SAli.Bahrami@Sun.COM Elf_Arhdr *arhdr; 1549646SAli.Bahrami@Sun.COM Elf *_elf = NULL; 1559646SAli.Bahrami@Sun.COM int found = 0; 1569646SAli.Bahrami@Sun.COM 1579646SAli.Bahrami@Sun.COM /* 1589646SAli.Bahrami@Sun.COM * Process each item within the archive until we find the first 1599646SAli.Bahrami@Sun.COM * ELF object, or alternatively another archive to recurse into. 1609646SAli.Bahrami@Sun.COM * Stop after analyzing the first plain object found. 1619646SAli.Bahrami@Sun.COM */ 1629646SAli.Bahrami@Sun.COM while (!found && ((_elf = elf_begin(fd, cmd, elf)) != NULL)) { 1639646SAli.Bahrami@Sun.COM if ((arhdr = elf_getarhdr(_elf)) == NULL) 1649646SAli.Bahrami@Sun.COM return (0); 1659646SAli.Bahrami@Sun.COM if (*arhdr->ar_name != '/') { 1669646SAli.Bahrami@Sun.COM switch (elf_kind(_elf)) { 1679646SAli.Bahrami@Sun.COM case ELF_K_AR: 1689646SAli.Bahrami@Sun.COM found = archive(fd, _elf, class_ret, mach_ret); 1699646SAli.Bahrami@Sun.COM break; 1709646SAli.Bahrami@Sun.COM case ELF_K_ELF: 1719646SAli.Bahrami@Sun.COM if (gelf_getclass(_elf) == ELFCLASS64) { 1729646SAli.Bahrami@Sun.COM Elf64_Ehdr *ehdr; 1739646SAli.Bahrami@Sun.COM 1749646SAli.Bahrami@Sun.COM if ((ehdr = elf64_getehdr(_elf)) == 1759646SAli.Bahrami@Sun.COM NULL) 1769646SAli.Bahrami@Sun.COM break; 1779646SAli.Bahrami@Sun.COM *class_ret = ehdr->e_ident[EI_CLASS]; 1789646SAli.Bahrami@Sun.COM *mach_ret = ehdr->e_machine; 1799646SAli.Bahrami@Sun.COM } else { 1809646SAli.Bahrami@Sun.COM Elf32_Ehdr *ehdr; 1819646SAli.Bahrami@Sun.COM 1829646SAli.Bahrami@Sun.COM if ((ehdr = elf32_getehdr(_elf)) == 1839646SAli.Bahrami@Sun.COM NULL) 1849646SAli.Bahrami@Sun.COM break; 1859646SAli.Bahrami@Sun.COM *class_ret = ehdr->e_ident[EI_CLASS]; 1869646SAli.Bahrami@Sun.COM *mach_ret = ehdr->e_machine; 1879646SAli.Bahrami@Sun.COM } 1889646SAli.Bahrami@Sun.COM found = 1; 1899646SAli.Bahrami@Sun.COM break; 1909646SAli.Bahrami@Sun.COM } 1919646SAli.Bahrami@Sun.COM } 1929646SAli.Bahrami@Sun.COM 1939646SAli.Bahrami@Sun.COM cmd = elf_next(_elf); 1949646SAli.Bahrami@Sun.COM (void) elf_end(_elf); 1959646SAli.Bahrami@Sun.COM } 1969646SAli.Bahrami@Sun.COM 1979646SAli.Bahrami@Sun.COM return (found); 1989646SAli.Bahrami@Sun.COM } 1999646SAli.Bahrami@Sun.COM 2009646SAli.Bahrami@Sun.COM /* 2019646SAli.Bahrami@Sun.COM * Determine: 2029646SAli.Bahrami@Sun.COM * - ELFCLASS of resulting object (class) 2039646SAli.Bahrami@Sun.COM * - Whether user specified class of the linker (ldclass) 2049646SAli.Bahrami@Sun.COM * - ELF machine type of resulting object (m_mach) 2059646SAli.Bahrami@Sun.COM * 2069646SAli.Bahrami@Sun.COM * In order of priority, we determine this information as follows: 2079646SAli.Bahrami@Sun.COM * 2089646SAli.Bahrami@Sun.COM * - Command line options (-32, -64, -z altexec64, -z target). 2099646SAli.Bahrami@Sun.COM * - From the first plain object seen on the command line. (This is 2109646SAli.Bahrami@Sun.COM * by far the most common case.) 2119646SAli.Bahrami@Sun.COM * - From the first object contained within the first archive 2129646SAli.Bahrami@Sun.COM * on the command line. 2139646SAli.Bahrami@Sun.COM * - If all else fails, we assume a 32-bit object for the native machine. 2149646SAli.Bahrami@Sun.COM * 2159646SAli.Bahrami@Sun.COM * entry: 2169646SAli.Bahrami@Sun.COM * argc, argv - Command line argument vector 2179646SAli.Bahrami@Sun.COM * class_ret - Address of variable to receive ELFCLASS of output object 2189646SAli.Bahrami@Sun.COM * ldclass_ret - Address of variable to receive ELFCLASS of 2199646SAli.Bahrami@Sun.COM * linker to use. This will be ELFCLASS32/ELFCLASS64 if one 2209646SAli.Bahrami@Sun.COM * is explicitly specified, and ELFCLASSNONE otherwise. 2219646SAli.Bahrami@Sun.COM * ELFCLASSNONE therefore means that we should use the best 2229646SAli.Bahrami@Sun.COM * link-editor that the system/kernel will allow. 2239646SAli.Bahrami@Sun.COM */ 2249646SAli.Bahrami@Sun.COM static int 2259646SAli.Bahrami@Sun.COM process_args(int argc, char **argv, uchar_t *class_ret, uchar_t *ldclass_ret, 2266206Sab196087 Half *mach) 2270Sstevel@tonic-gate { 2289646SAli.Bahrami@Sun.COM uchar_t ldclass = ELFCLASSNONE, class = ELFCLASSNONE, ar_class; 2299646SAli.Bahrami@Sun.COM Half mach32 = EM_NONE, mach64 = EM_NONE, ar_mach; 2309646SAli.Bahrami@Sun.COM int c, ar_found = 0; 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate /* 2336206Sab196087 * In general, libld.so is responsible for processing the 2346206Sab196087 * command line options. The exception to this are those options 2356206Sab196087 * that contain information about which linker to run and the 2366206Sab196087 * class/machine of the output object. We examine the options 2376206Sab196087 * here looking for the following: 2386206Sab196087 * 2399646SAli.Bahrami@Sun.COM * -32 Produce an ELFCLASS32 object. This is the default, so 2409646SAli.Bahrami@Sun.COM * -32 is only needed when linking entirely from archives, 2419646SAli.Bahrami@Sun.COM * and the first archive contains a mix of 32 and 64-bit 2429646SAli.Bahrami@Sun.COM * objects, and the first object in that archive is 64-bit. 2439646SAli.Bahrami@Sun.COM * We do not expect this option to get much use, but it 2449646SAli.Bahrami@Sun.COM * ensures that the user can handle any situation. 2459646SAli.Bahrami@Sun.COM * 2469646SAli.Bahrami@Sun.COM * -64 Produce an ELFCLASS64 object. (Note that this will 2479646SAli.Bahrami@Sun.COM * indirectly cause the use of the 64-bit linker if 2489646SAli.Bahrami@Sun.COM * the system is 64-bit capable). The most common need 2499646SAli.Bahrami@Sun.COM * for this option is when linking a filter object entirely 2509646SAli.Bahrami@Sun.COM * from a mapfile. The less common case is when linking 2519646SAli.Bahrami@Sun.COM * entirely from archives, and the first archive contains 2529646SAli.Bahrami@Sun.COM * a mix of 32 and 64-bit objects, and the first object 2539646SAli.Bahrami@Sun.COM * in that archive is 32-bit. 2540Sstevel@tonic-gate * 2557636SRod.Evans@Sun.COM * -z altexec64 2566206Sab196087 * Use the 64-bit linker regardless of the class 2576206Sab196087 * of the output object. 2586206Sab196087 * 2596206Sab196087 * -z target=platform 2606206Sab196087 * Produce output object for the specified platform. 2619646SAli.Bahrami@Sun.COM * This option is needed when producing an object 2629646SAli.Bahrami@Sun.COM * for a non-native target entirely from a mapfile, 2639646SAli.Bahrami@Sun.COM * or when linking entirely from an archive containing 2649646SAli.Bahrami@Sun.COM * objects for multiple targets, and the first object 2659646SAli.Bahrami@Sun.COM * in the archive is not for the desired target. 2666206Sab196087 * 2679646SAli.Bahrami@Sun.COM * If we've already processed an object and we find -32/-64, and 2689646SAli.Bahrami@Sun.COM * the object is of the wrong class, we have an error condition. 2699646SAli.Bahrami@Sun.COM * We ignore it here, and let it fall through to libld, where the 2709646SAli.Bahrami@Sun.COM * proper diagnosis and error message will occur. 2710Sstevel@tonic-gate */ 2720Sstevel@tonic-gate opterr = 0; 2737636SRod.Evans@Sun.COM optind = 1; 2747636SRod.Evans@Sun.COM getmore: 2757636SRod.Evans@Sun.COM while ((c = ld_getopt(0, optind, argc, argv)) != -1) { 2760Sstevel@tonic-gate switch (c) { 2779646SAli.Bahrami@Sun.COM case '3': 2789646SAli.Bahrami@Sun.COM if (strncmp(optarg, MSG_ORIG(MSG_ARG_TWO), 2799646SAli.Bahrami@Sun.COM MSG_ARG_TWO_SIZE) == 0) 2809646SAli.Bahrami@Sun.COM class = ELFCLASS32; 2819646SAli.Bahrami@Sun.COM break; 2829646SAli.Bahrami@Sun.COM 2837636SRod.Evans@Sun.COM case '6': 2847636SRod.Evans@Sun.COM if (strncmp(optarg, MSG_ORIG(MSG_ARG_FOUR), 2857636SRod.Evans@Sun.COM MSG_ARG_FOUR_SIZE) == 0) 2869646SAli.Bahrami@Sun.COM class = ELFCLASS64; 2877636SRod.Evans@Sun.COM break; 2886206Sab196087 2897636SRod.Evans@Sun.COM case 'z': 2907636SRod.Evans@Sun.COM #if !defined(_LP64) 2917636SRod.Evans@Sun.COM /* -z altexec64 */ 2927636SRod.Evans@Sun.COM if (strncmp(optarg, MSG_ORIG(MSG_ARG_ALTEXEC64), 2937636SRod.Evans@Sun.COM MSG_ARG_ALTEXEC64_SIZE) == 0) { 2949646SAli.Bahrami@Sun.COM ldclass = ELFCLASS64; 2957636SRod.Evans@Sun.COM break; 2967636SRod.Evans@Sun.COM } 2977636SRod.Evans@Sun.COM #endif 2987636SRod.Evans@Sun.COM /* -z target=platform */ 2997636SRod.Evans@Sun.COM if (strncmp(optarg, MSG_ORIG(MSG_ARG_TARGET), 3007636SRod.Evans@Sun.COM MSG_ARG_TARGET_SIZE) == 0) { 3017636SRod.Evans@Sun.COM char *pstr = optarg + MSG_ARG_TARGET_SIZE; 3026206Sab196087 3037636SRod.Evans@Sun.COM if (strcasecmp(pstr, 3047636SRod.Evans@Sun.COM MSG_ORIG(MSG_TARG_SPARC)) == 0) { 3057636SRod.Evans@Sun.COM mach32 = EM_SPARC; 3067636SRod.Evans@Sun.COM mach64 = EM_SPARCV9; 3077636SRod.Evans@Sun.COM } else if (strcasecmp(pstr, 3087636SRod.Evans@Sun.COM MSG_ORIG(MSG_TARG_X86)) == 0) { 3097636SRod.Evans@Sun.COM mach32 = EM_386; 3107636SRod.Evans@Sun.COM mach64 = EM_AMD64; 3117636SRod.Evans@Sun.COM } else { 3127636SRod.Evans@Sun.COM eprintf(0, ERR_FATAL, 3137636SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_BADTARG), pstr); 3147636SRod.Evans@Sun.COM return (1); 3156206Sab196087 } 3167636SRod.Evans@Sun.COM } 3177636SRod.Evans@Sun.COM break; 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate /* 3222647Srie * Continue to look for the first ELF object to determine the class of 3239646SAli.Bahrami@Sun.COM * objects to operate on. At the same time, look for the first archive 3249646SAli.Bahrami@Sun.COM * of ELF objects --- if no plain ELF object is specified, the type 3259646SAli.Bahrami@Sun.COM * of the first ELF object in the first archive will be used. If 3269646SAli.Bahrami@Sun.COM * there is no object, and no archive, then we fall back to a 32-bit 3279646SAli.Bahrami@Sun.COM * object for the native machine. 3280Sstevel@tonic-gate */ 3290Sstevel@tonic-gate for (; optind < argc; optind++) { 3300Sstevel@tonic-gate int fd; 3319646SAli.Bahrami@Sun.COM FILE_HDR hdr; 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate /* 3340Sstevel@tonic-gate * If we detect some more options return to getopt(). 3350Sstevel@tonic-gate * Checking argv[optind][1] against null prevents a forever 3360Sstevel@tonic-gate * loop if an unadorned `-' argument is passed to us. 3370Sstevel@tonic-gate */ 3380Sstevel@tonic-gate if (argv[optind][0] == '-') { 3390Sstevel@tonic-gate if (argv[optind][1] == '\0') 3400Sstevel@tonic-gate continue; 3410Sstevel@tonic-gate else 3420Sstevel@tonic-gate goto getmore; 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate 3452647Srie /* 3466206Sab196087 * If we've already determined the object class and 3476206Sab196087 * machine type, continue to the next argument. Only 3486206Sab196087 * the first object contributes to this decision, and 3496206Sab196087 * there's no value to opening or examing the subsequent 3506206Sab196087 * ones. We do need to keep going though, because there 3516206Sab196087 * may be additional options that might affect our 3526206Sab196087 * class/machine decision. 3532647Srie */ 3549646SAli.Bahrami@Sun.COM if ((class != ELFCLASSNONE) && (mach32 != EM_NONE)) 3552647Srie continue; 3562647Srie 3572647Srie /* 3589646SAli.Bahrami@Sun.COM * Open the file and determine if it is an object. We are 3599646SAli.Bahrami@Sun.COM * looking for ELF objects, or archives of ELF objects. 3609646SAli.Bahrami@Sun.COM * 3619646SAli.Bahrami@Sun.COM * Plain objects are simple, and are the common case, so 3629646SAli.Bahrami@Sun.COM * we examine them directly and avoid the map-unmap-map 3639646SAli.Bahrami@Sun.COM * that would occur if we used libelf. Archives are too 3649646SAli.Bahrami@Sun.COM * complex to be worth accessing directly, so if we identify 3659646SAli.Bahrami@Sun.COM * an archive, we use libelf on it and accept the cost. 3662647Srie */ 3670Sstevel@tonic-gate if ((fd = open(argv[optind], O_RDONLY)) == -1) { 3680Sstevel@tonic-gate int err = errno; 3690Sstevel@tonic-gate 3701618Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 3710Sstevel@tonic-gate argv[optind], strerror(err)); 3722647Srie return (1); 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate 3759646SAli.Bahrami@Sun.COM if (pread(fd, &hdr, sizeof (hdr), 0) != sizeof (hdr)) { 3769646SAli.Bahrami@Sun.COM (void) close(fd); 3779646SAli.Bahrami@Sun.COM continue; 3789646SAli.Bahrami@Sun.COM } 3799646SAli.Bahrami@Sun.COM 3809646SAli.Bahrami@Sun.COM if ((hdr.ehdr.e_ident[EI_MAG0] == ELFMAG0) && 3819646SAli.Bahrami@Sun.COM (hdr.ehdr.e_ident[EI_MAG1] == ELFMAG1) && 3829646SAli.Bahrami@Sun.COM (hdr.ehdr.e_ident[EI_MAG2] == ELFMAG2) && 3839646SAli.Bahrami@Sun.COM (hdr.ehdr.e_ident[EI_MAG3] == ELFMAG3)) { 3849646SAli.Bahrami@Sun.COM if (class == ELFCLASSNONE) { 3859646SAli.Bahrami@Sun.COM class = hdr.ehdr.e_ident[EI_CLASS]; 3869646SAli.Bahrami@Sun.COM if ((class != ELFCLASS32) && 3879646SAli.Bahrami@Sun.COM (class != ELFCLASS64)) 3889646SAli.Bahrami@Sun.COM class = ELFCLASSNONE; 3896206Sab196087 } 3906206Sab196087 3916206Sab196087 if (mach32 == EM_NONE) { 3926206Sab196087 int one = 1; 3936206Sab196087 uchar_t *one_p = (uchar_t *)&one; 3946206Sab196087 int ld_elfdata; 3956206Sab196087 3966206Sab196087 ld_elfdata = (one_p[0] == 1) ? 3976206Sab196087 ELFDATA2LSB : ELFDATA2MSB; 3986206Sab196087 /* 3996206Sab196087 * Both the 32 and 64-bit versions get the 4006206Sab196087 * type from the object. If the user has 4016206Sab196087 * asked for an inconsistant class/machine 4026206Sab196087 * combination, libld will catch it. 4036206Sab196087 */ 4046206Sab196087 mach32 = mach64 = 4059646SAli.Bahrami@Sun.COM (ld_elfdata == hdr.ehdr.e_ident[EI_DATA]) ? 4069646SAli.Bahrami@Sun.COM hdr.ehdr.e_machine : 4079646SAli.Bahrami@Sun.COM BSWAP_HALF(hdr.ehdr.e_machine); 4086206Sab196087 } 4099646SAli.Bahrami@Sun.COM } else if (!ar_found && 4109646SAli.Bahrami@Sun.COM (memcmp(&hdr.armag, ARMAG, SARMAG) == 0)) { 4119646SAli.Bahrami@Sun.COM Elf *elf; 4129646SAli.Bahrami@Sun.COM 4139646SAli.Bahrami@Sun.COM (void) elf_version(EV_CURRENT); 4149646SAli.Bahrami@Sun.COM if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 4159646SAli.Bahrami@Sun.COM (void) close(fd); 4169646SAli.Bahrami@Sun.COM continue; 4179646SAli.Bahrami@Sun.COM } 4189646SAli.Bahrami@Sun.COM if (elf_kind(elf) == ELF_K_AR) 4199646SAli.Bahrami@Sun.COM ar_found = 4209646SAli.Bahrami@Sun.COM archive(fd, elf, &ar_class, &ar_mach); 4219646SAli.Bahrami@Sun.COM (void) elf_end(elf); 4220Sstevel@tonic-gate } 4236206Sab196087 4240Sstevel@tonic-gate (void) close(fd); 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate /* 4289646SAli.Bahrami@Sun.COM * ELFCLASS of output object: If we did not establish a class from a 4299646SAli.Bahrami@Sun.COM * command option, or from the first plain object, then use the class 4309646SAli.Bahrami@Sun.COM * from the first archive, and failing that, default to 32-bit. 4310Sstevel@tonic-gate */ 4329646SAli.Bahrami@Sun.COM if (class == ELFCLASSNONE) 4339646SAli.Bahrami@Sun.COM class = ar_found ? ar_class : ELFCLASS32; 4349646SAli.Bahrami@Sun.COM *class_ret = class; 4356206Sab196087 4369646SAli.Bahrami@Sun.COM /* ELFCLASS of link-editor to use */ 4379646SAli.Bahrami@Sun.COM *ldclass_ret = ldclass; 4380Sstevel@tonic-gate 4396206Sab196087 /* 4409646SAli.Bahrami@Sun.COM * Machine type of output object: If we did not establish a machine 4419646SAli.Bahrami@Sun.COM * type from the command line, or from the first plain object, then 4429646SAli.Bahrami@Sun.COM * use the machine established by the first archive, and failing that, 4439646SAli.Bahrami@Sun.COM * use the native machine. 4446206Sab196087 */ 4459646SAli.Bahrami@Sun.COM *mach = (class == ELFCLASS64) ? mach64 : mach32; 4466206Sab196087 if (*mach == EM_NONE) 4479646SAli.Bahrami@Sun.COM if (ar_found) 4489646SAli.Bahrami@Sun.COM *mach = ar_mach; 4499646SAli.Bahrami@Sun.COM else 4509646SAli.Bahrami@Sun.COM *mach = (class == ELFCLASS64) ? M_MACH_64 : M_MACH_32; 4516206Sab196087 4522647Srie return (0); 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* 4567636SRod.Evans@Sun.COM * Process an LD_OPTIONS environment string. This routine is first called to 4577636SRod.Evans@Sun.COM * count the number of options, and second to initialize a new argument array 4587636SRod.Evans@Sun.COM * with each option. 4590Sstevel@tonic-gate */ 4600Sstevel@tonic-gate static int 4617636SRod.Evans@Sun.COM process_ldoptions(char *str, char **nargv) 4620Sstevel@tonic-gate { 4637636SRod.Evans@Sun.COM int argc = 0; 4647636SRod.Evans@Sun.COM char *arg = str; 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate /* 4677636SRod.Evans@Sun.COM * Walk the environment string processing any arguments that are 4687636SRod.Evans@Sun.COM * separated by white space. 4697636SRod.Evans@Sun.COM */ 4707636SRod.Evans@Sun.COM while (*str != '\0') { 4717636SRod.Evans@Sun.COM if (isspace(*str)) { 4727636SRod.Evans@Sun.COM /* 4737636SRod.Evans@Sun.COM * If a new argument array has been provided, terminate 4747636SRod.Evans@Sun.COM * the original environment string, and initialize the 4757636SRod.Evans@Sun.COM * appropriate argument array entry. 4767636SRod.Evans@Sun.COM */ 4777636SRod.Evans@Sun.COM if (nargv) { 4787636SRod.Evans@Sun.COM *str++ = '\0'; 4797636SRod.Evans@Sun.COM nargv[argc] = arg; 4807636SRod.Evans@Sun.COM } 4817636SRod.Evans@Sun.COM 4827636SRod.Evans@Sun.COM argc++; 4837636SRod.Evans@Sun.COM while (isspace(*str)) 4847636SRod.Evans@Sun.COM str++; 4857636SRod.Evans@Sun.COM arg = str; 4867636SRod.Evans@Sun.COM } else 4877636SRod.Evans@Sun.COM str++; 4887636SRod.Evans@Sun.COM } 4897636SRod.Evans@Sun.COM if (arg != str) { 4907636SRod.Evans@Sun.COM /* 4917636SRod.Evans@Sun.COM * If a new argument array has been provided, initialize the 4927636SRod.Evans@Sun.COM * final argument array entry. 4937636SRod.Evans@Sun.COM */ 4947636SRod.Evans@Sun.COM if (nargv) 4957636SRod.Evans@Sun.COM nargv[argc] = arg; 4967636SRod.Evans@Sun.COM argc++; 4977636SRod.Evans@Sun.COM } 4987636SRod.Evans@Sun.COM 4997636SRod.Evans@Sun.COM return (argc); 5007636SRod.Evans@Sun.COM } 5017636SRod.Evans@Sun.COM 5027636SRod.Evans@Sun.COM /* 5037636SRod.Evans@Sun.COM * Determine whether an LD_OPTIONS environment variable is set, and if so, 5047636SRod.Evans@Sun.COM * prepend environment string as a series of options to the argv array. 5057636SRod.Evans@Sun.COM */ 5067636SRod.Evans@Sun.COM static int 5077636SRod.Evans@Sun.COM prepend_ldoptions(int *argcp, char ***argvp) 5087636SRod.Evans@Sun.COM { 5097636SRod.Evans@Sun.COM int nargc; 5107636SRod.Evans@Sun.COM char **nargv, *ld_options; 5117636SRod.Evans@Sun.COM int err, count; 5127636SRod.Evans@Sun.COM 5137636SRod.Evans@Sun.COM if ((ld_options = getenv(MSG_ORIG(MSG_LD_OPTIONS))) == NULL) 5147636SRod.Evans@Sun.COM return (0); 5157636SRod.Evans@Sun.COM 5167636SRod.Evans@Sun.COM /* 517*10792SRod.Evans@Sun.COM * Get rid of any leading white space, and make sure the environment 518*10792SRod.Evans@Sun.COM * string has size. 519*10792SRod.Evans@Sun.COM */ 520*10792SRod.Evans@Sun.COM while (isspace(*ld_options)) 521*10792SRod.Evans@Sun.COM ld_options++; 522*10792SRod.Evans@Sun.COM if (*ld_options == '\0') 523*10792SRod.Evans@Sun.COM return (0); 524*10792SRod.Evans@Sun.COM 525*10792SRod.Evans@Sun.COM /* 5267636SRod.Evans@Sun.COM * Prevent modification of actual environment strings. 5277636SRod.Evans@Sun.COM */ 5287636SRod.Evans@Sun.COM if ((ld_options = strdup(ld_options)) == NULL) { 5297636SRod.Evans@Sun.COM err = errno; 5307636SRod.Evans@Sun.COM eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_ALLOC), strerror(err)); 5317636SRod.Evans@Sun.COM return (1); 5327636SRod.Evans@Sun.COM } 5337636SRod.Evans@Sun.COM 5347636SRod.Evans@Sun.COM /* 5357636SRod.Evans@Sun.COM * Determine the number of options provided. 5360Sstevel@tonic-gate */ 5377636SRod.Evans@Sun.COM nargc = process_ldoptions(ld_options, NULL); 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate /* 5400Sstevel@tonic-gate * Allocate a new argv array big enough to hold the new options from 5410Sstevel@tonic-gate * the environment string and the old argv options. 5420Sstevel@tonic-gate */ 5437636SRod.Evans@Sun.COM if ((nargv = malloc((nargc + *argcp + 1) * sizeof (char *))) == NULL) { 5447636SRod.Evans@Sun.COM err = errno; 5451618Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_ALLOC), strerror(err)); 5467636SRod.Evans@Sun.COM return (1); 5471618Srie } 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate /* 5500Sstevel@tonic-gate * Initialize first element of new argv array to be the first element 5510Sstevel@tonic-gate * of the old argv array (ie. calling programs name). Then add the new 5520Sstevel@tonic-gate * args obtained from the environment. 5530Sstevel@tonic-gate */ 5540Sstevel@tonic-gate nargc = 0; 5557636SRod.Evans@Sun.COM nargv[nargc++] = (*argvp)[0]; 5567636SRod.Evans@Sun.COM nargc += process_ldoptions(ld_options, &nargv[nargc]); 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate /* 5590Sstevel@tonic-gate * Now add the original argv array (skipping argv[0]) to the end of the 5607636SRod.Evans@Sun.COM * new argv array, and re-vector argc and argv to reference this new 5617636SRod.Evans@Sun.COM * array 5620Sstevel@tonic-gate */ 5637636SRod.Evans@Sun.COM for (count = 1; count < *argcp; count++, nargc++) 5640Sstevel@tonic-gate nargv[nargc] = (*argvp)[count]; 5657636SRod.Evans@Sun.COM 5667636SRod.Evans@Sun.COM nargv[nargc] = NULL; 5677636SRod.Evans@Sun.COM 5687636SRod.Evans@Sun.COM *argcp = nargc; 5690Sstevel@tonic-gate *argvp = nargv; 5700Sstevel@tonic-gate 5717636SRod.Evans@Sun.COM return (0); 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate /* 5751618Srie * Check to see if there is a LD_ALTEXEC=<path to alternate ld> in the 5761618Srie * environment. If so, first null the environment variable out, and then 5771618Srie * exec() the binary pointed to by the environment variable, passing the same 5781618Srie * arguments as the originating process. This mechanism permits using 5791618Srie * alternate link-editors (debugging/developer copies) even in complex build 5801618Srie * environments. 5810Sstevel@tonic-gate */ 5822647Srie static int 5830Sstevel@tonic-gate ld_altexec(char **argv, char **envp) 5840Sstevel@tonic-gate { 5850Sstevel@tonic-gate char *execstr; 5860Sstevel@tonic-gate char **str; 5872647Srie int err; 5882647Srie 5890Sstevel@tonic-gate for (str = envp; *str; str++) { 5900Sstevel@tonic-gate if (strncmp(*str, MSG_ORIG(MSG_LD_ALTEXEC), 5910Sstevel@tonic-gate MSG_LD_ALTEXEC_SIZE) == 0) { 5920Sstevel@tonic-gate break; 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate /* 5972647Srie * If LD_ALTEXEC isn't set, return to continue executing the present 5982647Srie * link-editor. 5992647Srie */ 6002647Srie if (*str == 0) 6012647Srie return (0); 6022647Srie 6032647Srie /* 6042647Srie * Get a pointer to the actual string. If it's a null entry, return. 6050Sstevel@tonic-gate */ 6060Sstevel@tonic-gate execstr = strdup(*str + MSG_LD_ALTEXEC_SIZE); 6070Sstevel@tonic-gate if (*execstr == '\0') 6082647Srie return (0); 6092647Srie 6100Sstevel@tonic-gate /* 6110Sstevel@tonic-gate * Null out the LD_ALTEXEC= environment entry. 6120Sstevel@tonic-gate */ 6130Sstevel@tonic-gate (*str)[MSG_LD_ALTEXEC_SIZE] = '\0'; 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate /* 6160Sstevel@tonic-gate * Set argv[0] to point to our new linker 6170Sstevel@tonic-gate */ 6180Sstevel@tonic-gate argv[0] = execstr; 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate /* 6210Sstevel@tonic-gate * And attempt to execute it. 6220Sstevel@tonic-gate */ 6230Sstevel@tonic-gate (void) execve(execstr, argv, envp); 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate /* 6262647Srie * If the exec() fails, return a failure indication. 6270Sstevel@tonic-gate */ 6282647Srie err = errno; 6292647Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_EXEC), execstr, 6302647Srie strerror(err)); 6312647Srie return (1); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate int 6350Sstevel@tonic-gate main(int argc, char **argv, char **envp) 6360Sstevel@tonic-gate { 6377636SRod.Evans@Sun.COM char **oargv = argv; 6389646SAli.Bahrami@Sun.COM uchar_t class, ldclass, checkclass; 6396206Sab196087 Half mach; 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate /* 6420Sstevel@tonic-gate * Establish locale. 6430Sstevel@tonic-gate */ 6440Sstevel@tonic-gate (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 6450Sstevel@tonic-gate (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate /* 6482647Srie * Execute an alternate linker if the LD_ALTEXEC environment variable is 6492647Srie * set. If a specified alternative could not be found, bail. 6500Sstevel@tonic-gate */ 6512647Srie if (ld_altexec(argv, envp)) 6522647Srie return (1); 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate /* 6550Sstevel@tonic-gate * Check the LD_OPTIONS environment variable, and if present prepend 6560Sstevel@tonic-gate * the arguments specified to the command line argument list. 6570Sstevel@tonic-gate */ 6587636SRod.Evans@Sun.COM if (prepend_ldoptions(&argc, &argv)) 6597636SRod.Evans@Sun.COM return (1); 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate /* 6626206Sab196087 * Examine the command arguments to determine: 6636206Sab196087 * - object class 6646206Sab196087 * - link-editor class 6656206Sab196087 * - target machine 6660Sstevel@tonic-gate */ 6679646SAli.Bahrami@Sun.COM if (process_args(argc, argv, &class, &ldclass, &mach)) 6680Sstevel@tonic-gate return (1); 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* 6719646SAli.Bahrami@Sun.COM * Unless a 32-bit link-editor was explicitly requested, try 6729646SAli.Bahrami@Sun.COM * to exec the 64-bit version. 6730Sstevel@tonic-gate */ 6749646SAli.Bahrami@Sun.COM if (ldclass != ELFCLASS32) 6752647Srie checkclass = conv_check_native(oargv, envp); 6762647Srie 6779646SAli.Bahrami@Sun.COM /* 6789646SAli.Bahrami@Sun.COM * If an attempt to exec the 64-bit link-editor fails: 6799646SAli.Bahrami@Sun.COM * - Bail if the 64-bit linker was explicitly requested 6809646SAli.Bahrami@Sun.COM * - Continue quietly if the 64-bit linker was not requested. 6819646SAli.Bahrami@Sun.COM * This is undoubtedly due to hardware/kernel limitations, 6829646SAli.Bahrami@Sun.COM * and therefore represents the best we can do. Note that 6839646SAli.Bahrami@Sun.COM * the 32-bit linker is capable of linking anything the 6849646SAli.Bahrami@Sun.COM * 64-bit version is, subject to a 4GB limit on memory, and 6859646SAli.Bahrami@Sun.COM * 2GB object size. 6869646SAli.Bahrami@Sun.COM */ 6872647Srie if ((ldclass == ELFCLASS64) && (checkclass != ELFCLASS64)) { 6882647Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_64)); 6892647Srie return (1); 6902647Srie } 6910Sstevel@tonic-gate 6929646SAli.Bahrami@Sun.COM /* Call the libld entry point for the specified ELFCLASS */ 6939646SAli.Bahrami@Sun.COM if (class == ELFCLASS64) 6946206Sab196087 return (ld64_main(argc, argv, mach)); 6951618Srie else 6966206Sab196087 return (ld32_main(argc, argv, mach)); 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate /* 7009646SAli.Bahrami@Sun.COM * We supply this function for the msg module 7010Sstevel@tonic-gate */ 7020Sstevel@tonic-gate const char * 7030Sstevel@tonic-gate _ld_msg(Msg mid) 7040Sstevel@tonic-gate { 7050Sstevel@tonic-gate return (gettext(MSG_ORIG(mid))); 7060Sstevel@tonic-gate } 707