17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 215aefb655Srie 227c478bd9Sstevel@tonic-gate /* 23*1007fd6fSAli Bahrami * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <stdio.h> 277c478bd9Sstevel@tonic-gate #include <stdlib.h> 287c478bd9Sstevel@tonic-gate #include <unistd.h> 297c478bd9Sstevel@tonic-gate #include <stdarg.h> 307c478bd9Sstevel@tonic-gate #include <string.h> 31ba2be530Sab196087 #include <strings.h> 327c478bd9Sstevel@tonic-gate #include <errno.h> 337c478bd9Sstevel@tonic-gate #include <fcntl.h> 347c478bd9Sstevel@tonic-gate #include <libintl.h> 357c478bd9Sstevel@tonic-gate #include <locale.h> 367c478bd9Sstevel@tonic-gate #include <fcntl.h> 3756e2cc86SAli Bahrami #include <ar.h> 3856e2cc86SAli Bahrami #include <gelf.h> 397c478bd9Sstevel@tonic-gate #include "conv.h" 407c478bd9Sstevel@tonic-gate #include "libld.h" 41ba2be530Sab196087 #include "machdep.h" 427c478bd9Sstevel@tonic-gate #include "msg.h" 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * The following prevent us from having to include ctype.h which defines these 467c478bd9Sstevel@tonic-gate * functions as macros which reference the __ctype[] array. Go through .plt's 477c478bd9Sstevel@tonic-gate * to get to these functions in libc rather than have every invocation of ld 487c478bd9Sstevel@tonic-gate * have to suffer the R_SPARC_COPY overhead of the __ctype[] array. 497c478bd9Sstevel@tonic-gate */ 507c478bd9Sstevel@tonic-gate extern int isspace(int); 517c478bd9Sstevel@tonic-gate 525aefb655Srie /* 5356e2cc86SAli Bahrami * We examine ELF objects, and archives containing ELF objects, in order 5456e2cc86SAli Bahrami * to determine the ELFCLASS of the resulting object and/or the linker to be 5556e2cc86SAli Bahrami * used. We want to avoid the overhead of libelf for this, at least until 5656e2cc86SAli Bahrami * we are certain that we need it, so we start by reading bytes from 5756e2cc86SAli Bahrami * the beginning of the file. This type defines the buffer used to read 5856e2cc86SAli Bahrami * these initial bytes. 5956e2cc86SAli Bahrami * 6056e2cc86SAli Bahrami * A plain ELF object will start with an ELF header, whereas an archive 6156e2cc86SAli Bahrami * starts with a magic string (ARMAG) that is SARMAG bytes long. Any valid 6256e2cc86SAli Bahrami * ELF file or archive will contain more bytes than this buffer, so any 6356e2cc86SAli Bahrami * file shorter than this can be safely assummed not to be of interest. 6456e2cc86SAli Bahrami * 6556e2cc86SAli Bahrami * The ELF header for ELFCLASS32 and ELFCLASS64 are identical up through the 6656e2cc86SAli Bahrami * the e_version field, and all the information we require is found in this 6756e2cc86SAli Bahrami * common prefix. Furthermore, this cannot change, as the layout of an ELF 6856e2cc86SAli Bahrami * header is fixed by the ELF ABI. Hence, the ehdr part of this union is 6956e2cc86SAli Bahrami * not a full ELF header, but only the class-independent prefix that we need. 7056e2cc86SAli Bahrami * 7156e2cc86SAli Bahrami * As this is a raw (non-libelf) read, we are responsible for handling any 7256e2cc86SAli Bahrami * byte order difference between the object and the system running this 7356e2cc86SAli Bahrami * program when we read any datum larger than a byte (i.e. e_machine) from 7456e2cc86SAli Bahrami * this header. 7556e2cc86SAli Bahrami */ 7656e2cc86SAli Bahrami typedef union { 7756e2cc86SAli Bahrami struct { /* Must match start of ELFxx_Ehdr in <sys/elf.h> */ 7856e2cc86SAli Bahrami uchar_t e_ident[EI_NIDENT]; /* ident bytes */ 7956e2cc86SAli Bahrami Half e_type; /* file type */ 8056e2cc86SAli Bahrami Half e_machine; /* target machine */ 8156e2cc86SAli Bahrami } ehdr; 8256e2cc86SAli Bahrami char armag[SARMAG]; 8356e2cc86SAli Bahrami } FILE_HDR; 8456e2cc86SAli Bahrami 8556e2cc86SAli Bahrami 8656e2cc86SAli Bahrami /* 875aefb655Srie * Print a message to stdout 885aefb655Srie */ 895aefb655Srie void 90*1007fd6fSAli Bahrami veprintf(Lm_list *lml, Error error, const char *format, va_list args) 915aefb655Srie { 92*1007fd6fSAli Bahrami static const char *strings[ERR_NUM]; 935aefb655Srie 945aefb655Srie #if defined(lint) 955aefb655Srie /* 965aefb655Srie * The lml argument is only meaningful for diagnostics sent to ld.so.1. 975aefb655Srie * Supress the lint error by making a dummy assignment. 985aefb655Srie */ 995aefb655Srie lml = 0; 1005aefb655Srie #endif 101*1007fd6fSAli Bahrami /* 102*1007fd6fSAli Bahrami * For error types we issue a prefix for, make sure the necessary 103*1007fd6fSAli Bahrami * string has been internationalized and is ready. 104*1007fd6fSAli Bahrami */ 105*1007fd6fSAli Bahrami switch (error) { 106*1007fd6fSAli Bahrami case ERR_WARNING_NF: 107*1007fd6fSAli Bahrami if (strings[ERR_WARNING_NF] == NULL) 108*1007fd6fSAli Bahrami strings[ERR_WARNING_NF] = MSG_INTL(MSG_ERR_WARNING); 109*1007fd6fSAli Bahrami break; 110*1007fd6fSAli Bahrami case ERR_WARNING: 111*1007fd6fSAli Bahrami if (strings[ERR_WARNING] == NULL) 112*1007fd6fSAli Bahrami strings[ERR_WARNING] = MSG_INTL(MSG_ERR_WARNING); 113*1007fd6fSAli Bahrami break; 114*1007fd6fSAli Bahrami case ERR_GUIDANCE: 115*1007fd6fSAli Bahrami if (strings[ERR_GUIDANCE] == NULL) 116*1007fd6fSAli Bahrami strings[ERR_GUIDANCE] = MSG_INTL(MSG_ERR_GUIDANCE); 117*1007fd6fSAli Bahrami break; 118*1007fd6fSAli Bahrami case ERR_FATAL: 119*1007fd6fSAli Bahrami if (strings[ERR_FATAL] == NULL) 1205aefb655Srie strings[ERR_FATAL] = MSG_INTL(MSG_ERR_FATAL); 121*1007fd6fSAli Bahrami break; 122*1007fd6fSAli Bahrami case ERR_ELF: 123*1007fd6fSAli Bahrami if (strings[ERR_ELF] == NULL) 1245aefb655Srie strings[ERR_ELF] = MSG_INTL(MSG_ERR_ELF); 1255aefb655Srie } 1265aefb655Srie 127*1007fd6fSAli Bahrami /* If strings[] element for our error type is non-NULL, issue prefix */ 128*1007fd6fSAli Bahrami if (strings[error] != NULL) { 129*1007fd6fSAli Bahrami (void) fputs(MSG_ORIG(MSG_STR_LDDIAG), stderr); 130*1007fd6fSAli Bahrami (void) fputs(strings[error], stderr); 131*1007fd6fSAli Bahrami } 132*1007fd6fSAli Bahrami 1335aefb655Srie (void) vfprintf(stderr, format, args); 1345aefb655Srie if (error == ERR_ELF) { 1355aefb655Srie int elferr; 1365aefb655Srie 1375aefb655Srie if ((elferr = elf_errno()) != 0) 1385aefb655Srie (void) fprintf(stderr, MSG_ORIG(MSG_STR_ELFDIAG), 1395aefb655Srie elf_errmsg(elferr)); 1405aefb655Srie } 1415aefb655Srie (void) fprintf(stderr, MSG_ORIG(MSG_STR_NL)); 1425aefb655Srie (void) fflush(stderr); 143*1007fd6fSAli Bahrami } 144*1007fd6fSAli Bahrami 145*1007fd6fSAli Bahrami 146*1007fd6fSAli Bahrami /* 147*1007fd6fSAli Bahrami * Print a message to stdout 148*1007fd6fSAli Bahrami */ 149*1007fd6fSAli Bahrami /* VARARGS3 */ 150*1007fd6fSAli Bahrami void 151*1007fd6fSAli Bahrami eprintf(Lm_list *lml, Error error, const char *format, ...) 152*1007fd6fSAli Bahrami { 153*1007fd6fSAli Bahrami va_list args; 154*1007fd6fSAli Bahrami 155*1007fd6fSAli Bahrami va_start(args, format); 156*1007fd6fSAli Bahrami veprintf(lml, error, format, args); 1575aefb655Srie va_end(args); 1585aefb655Srie } 1595aefb655Srie 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* 16256e2cc86SAli Bahrami * Examine the first object in an archive to determine its ELFCLASS 16356e2cc86SAli Bahrami * and machine type. 16456e2cc86SAli Bahrami * 16556e2cc86SAli Bahrami * entry: 16656e2cc86SAli Bahrami * fd - Open file descriptor for file 16756e2cc86SAli Bahrami * elf - libelf ELF descriptor 16856e2cc86SAli Bahrami * class_ret, mach_ret - Address of variables to receive ELFCLASS 16956e2cc86SAli Bahrami * and machine type. 17056e2cc86SAli Bahrami * 17156e2cc86SAli Bahrami * exit: 17256e2cc86SAli Bahrami * On success, *class_ret and *mach_ret are filled in, and True (1) 17356e2cc86SAli Bahrami * is returned. On failure, False (0) is returned. 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate static int 17656e2cc86SAli Bahrami archive(int fd, Elf *elf, uchar_t *class_ret, Half *mach_ret) 17756e2cc86SAli Bahrami { 17856e2cc86SAli Bahrami Elf_Cmd cmd = ELF_C_READ; 17956e2cc86SAli Bahrami Elf_Arhdr *arhdr; 18056e2cc86SAli Bahrami Elf *_elf = NULL; 18156e2cc86SAli Bahrami int found = 0; 18256e2cc86SAli Bahrami 18356e2cc86SAli Bahrami /* 18456e2cc86SAli Bahrami * Process each item within the archive until we find the first 18556e2cc86SAli Bahrami * ELF object, or alternatively another archive to recurse into. 18656e2cc86SAli Bahrami * Stop after analyzing the first plain object found. 18756e2cc86SAli Bahrami */ 18856e2cc86SAli Bahrami while (!found && ((_elf = elf_begin(fd, cmd, elf)) != NULL)) { 18956e2cc86SAli Bahrami if ((arhdr = elf_getarhdr(_elf)) == NULL) 19056e2cc86SAli Bahrami return (0); 19156e2cc86SAli Bahrami if (*arhdr->ar_name != '/') { 19256e2cc86SAli Bahrami switch (elf_kind(_elf)) { 19356e2cc86SAli Bahrami case ELF_K_AR: 19456e2cc86SAli Bahrami found = archive(fd, _elf, class_ret, mach_ret); 19556e2cc86SAli Bahrami break; 19656e2cc86SAli Bahrami case ELF_K_ELF: 19756e2cc86SAli Bahrami if (gelf_getclass(_elf) == ELFCLASS64) { 19856e2cc86SAli Bahrami Elf64_Ehdr *ehdr; 19956e2cc86SAli Bahrami 20056e2cc86SAli Bahrami if ((ehdr = elf64_getehdr(_elf)) == 20156e2cc86SAli Bahrami NULL) 20256e2cc86SAli Bahrami break; 20356e2cc86SAli Bahrami *class_ret = ehdr->e_ident[EI_CLASS]; 20456e2cc86SAli Bahrami *mach_ret = ehdr->e_machine; 20556e2cc86SAli Bahrami } else { 20656e2cc86SAli Bahrami Elf32_Ehdr *ehdr; 20756e2cc86SAli Bahrami 20856e2cc86SAli Bahrami if ((ehdr = elf32_getehdr(_elf)) == 20956e2cc86SAli Bahrami NULL) 21056e2cc86SAli Bahrami break; 21156e2cc86SAli Bahrami *class_ret = ehdr->e_ident[EI_CLASS]; 21256e2cc86SAli Bahrami *mach_ret = ehdr->e_machine; 21356e2cc86SAli Bahrami } 21456e2cc86SAli Bahrami found = 1; 21556e2cc86SAli Bahrami break; 21656e2cc86SAli Bahrami } 21756e2cc86SAli Bahrami } 21856e2cc86SAli Bahrami 21956e2cc86SAli Bahrami cmd = elf_next(_elf); 22056e2cc86SAli Bahrami (void) elf_end(_elf); 22156e2cc86SAli Bahrami } 22256e2cc86SAli Bahrami 22356e2cc86SAli Bahrami return (found); 22456e2cc86SAli Bahrami } 22556e2cc86SAli Bahrami 22656e2cc86SAli Bahrami /* 22756e2cc86SAli Bahrami * Determine: 22856e2cc86SAli Bahrami * - ELFCLASS of resulting object (class) 22956e2cc86SAli Bahrami * - Whether user specified class of the linker (ldclass) 23056e2cc86SAli Bahrami * - ELF machine type of resulting object (m_mach) 23156e2cc86SAli Bahrami * 23256e2cc86SAli Bahrami * In order of priority, we determine this information as follows: 23356e2cc86SAli Bahrami * 23456e2cc86SAli Bahrami * - Command line options (-32, -64, -z altexec64, -z target). 23556e2cc86SAli Bahrami * - From the first plain object seen on the command line. (This is 23656e2cc86SAli Bahrami * by far the most common case.) 23756e2cc86SAli Bahrami * - From the first object contained within the first archive 23856e2cc86SAli Bahrami * on the command line. 23956e2cc86SAli Bahrami * - If all else fails, we assume a 32-bit object for the native machine. 24056e2cc86SAli Bahrami * 24156e2cc86SAli Bahrami * entry: 24256e2cc86SAli Bahrami * argc, argv - Command line argument vector 24356e2cc86SAli Bahrami * class_ret - Address of variable to receive ELFCLASS of output object 24456e2cc86SAli Bahrami * ldclass_ret - Address of variable to receive ELFCLASS of 24556e2cc86SAli Bahrami * linker to use. This will be ELFCLASS32/ELFCLASS64 if one 24656e2cc86SAli Bahrami * is explicitly specified, and ELFCLASSNONE otherwise. 24756e2cc86SAli Bahrami * ELFCLASSNONE therefore means that we should use the best 24856e2cc86SAli Bahrami * link-editor that the system/kernel will allow. 24956e2cc86SAli Bahrami */ 25056e2cc86SAli Bahrami static int 25156e2cc86SAli Bahrami process_args(int argc, char **argv, uchar_t *class_ret, uchar_t *ldclass_ret, 252ba2be530Sab196087 Half *mach) 2537c478bd9Sstevel@tonic-gate { 25456e2cc86SAli Bahrami uchar_t ldclass = ELFCLASSNONE, class = ELFCLASSNONE, ar_class; 25556e2cc86SAli Bahrami Half mach32 = EM_NONE, mach64 = EM_NONE, ar_mach; 25656e2cc86SAli Bahrami int c, ar_found = 0; 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 259ba2be530Sab196087 * In general, libld.so is responsible for processing the 260ba2be530Sab196087 * command line options. The exception to this are those options 261ba2be530Sab196087 * that contain information about which linker to run and the 262ba2be530Sab196087 * class/machine of the output object. We examine the options 263ba2be530Sab196087 * here looking for the following: 2647c478bd9Sstevel@tonic-gate * 26556e2cc86SAli Bahrami * -32 Produce an ELFCLASS32 object. This is the default, so 26656e2cc86SAli Bahrami * -32 is only needed when linking entirely from archives, 26756e2cc86SAli Bahrami * and the first archive contains a mix of 32 and 64-bit 26856e2cc86SAli Bahrami * objects, and the first object in that archive is 64-bit. 26956e2cc86SAli Bahrami * We do not expect this option to get much use, but it 27056e2cc86SAli Bahrami * ensures that the user can handle any situation. 27156e2cc86SAli Bahrami * 27256e2cc86SAli Bahrami * -64 Produce an ELFCLASS64 object. (Note that this will 27356e2cc86SAli Bahrami * indirectly cause the use of the 64-bit linker if 27456e2cc86SAli Bahrami * the system is 64-bit capable). The most common need 27556e2cc86SAli Bahrami * for this option is when linking a filter object entirely 27656e2cc86SAli Bahrami * from a mapfile. The less common case is when linking 27756e2cc86SAli Bahrami * entirely from archives, and the first archive contains 27856e2cc86SAli Bahrami * a mix of 32 and 64-bit objects, and the first object 27956e2cc86SAli Bahrami * in that archive is 32-bit. 280ba2be530Sab196087 * 281ba2be530Sab196087 * -z altexec64 282ba2be530Sab196087 * Use the 64-bit linker regardless of the class 283ba2be530Sab196087 * of the output object. 284ba2be530Sab196087 * 285ba2be530Sab196087 * -z target=platform 286ba2be530Sab196087 * Produce output object for the specified platform. 28756e2cc86SAli Bahrami * This option is needed when producing an object 28856e2cc86SAli Bahrami * for a non-native target entirely from a mapfile, 28956e2cc86SAli Bahrami * or when linking entirely from an archive containing 29056e2cc86SAli Bahrami * objects for multiple targets, and the first object 29156e2cc86SAli Bahrami * in the archive is not for the desired target. 292ba2be530Sab196087 * 29356e2cc86SAli Bahrami * If we've already processed an object and we find -32/-64, and 29456e2cc86SAli Bahrami * the object is of the wrong class, we have an error condition. 29556e2cc86SAli Bahrami * We ignore it here, and let it fall through to libld, where the 29656e2cc86SAli Bahrami * proper diagnosis and error message will occur. 2977c478bd9Sstevel@tonic-gate */ 2987c478bd9Sstevel@tonic-gate opterr = 0; 29992a02081SRod Evans optind = 1; 30092a02081SRod Evans getmore: 30192a02081SRod Evans while ((c = ld_getopt(0, optind, argc, argv)) != -1) { 3027c478bd9Sstevel@tonic-gate switch (c) { 30356e2cc86SAli Bahrami case '3': 30456e2cc86SAli Bahrami if (strncmp(optarg, MSG_ORIG(MSG_ARG_TWO), 30556e2cc86SAli Bahrami MSG_ARG_TWO_SIZE) == 0) 30656e2cc86SAli Bahrami class = ELFCLASS32; 30756e2cc86SAli Bahrami break; 30856e2cc86SAli Bahrami 3097c478bd9Sstevel@tonic-gate case '6': 3107010c12aSrie if (strncmp(optarg, MSG_ORIG(MSG_ARG_FOUR), 3117010c12aSrie MSG_ARG_FOUR_SIZE) == 0) 31256e2cc86SAli Bahrami class = ELFCLASS64; 3137010c12aSrie break; 314ba2be530Sab196087 3157010c12aSrie case 'z': 316ba2be530Sab196087 #if !defined(_LP64) 317ba2be530Sab196087 /* -z altexec64 */ 3187010c12aSrie if (strncmp(optarg, MSG_ORIG(MSG_ARG_ALTEXEC64), 319ba2be530Sab196087 MSG_ARG_ALTEXEC64_SIZE) == 0) { 32056e2cc86SAli Bahrami ldclass = ELFCLASS64; 3217010c12aSrie break; 322ba2be530Sab196087 } 3237010c12aSrie #endif 324ba2be530Sab196087 /* -z target=platform */ 325ba2be530Sab196087 if (strncmp(optarg, MSG_ORIG(MSG_ARG_TARGET), 326ba2be530Sab196087 MSG_ARG_TARGET_SIZE) == 0) { 32792a02081SRod Evans char *pstr = optarg + MSG_ARG_TARGET_SIZE; 328ba2be530Sab196087 329ba2be530Sab196087 if (strcasecmp(pstr, 330ba2be530Sab196087 MSG_ORIG(MSG_TARG_SPARC)) == 0) { 331ba2be530Sab196087 mach32 = EM_SPARC; 332ba2be530Sab196087 mach64 = EM_SPARCV9; 333ba2be530Sab196087 } else if (strcasecmp(pstr, 334ba2be530Sab196087 MSG_ORIG(MSG_TARG_X86)) == 0) { 335ba2be530Sab196087 mach32 = EM_386; 336ba2be530Sab196087 mach64 = EM_AMD64; 337ba2be530Sab196087 } else { 338ba2be530Sab196087 eprintf(0, ERR_FATAL, 33992a02081SRod Evans MSG_INTL(MSG_ERR_BADTARG), pstr); 340ba2be530Sab196087 return (1); 341ba2be530Sab196087 } 342ba2be530Sab196087 } 343ba2be530Sab196087 break; 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* 3487010c12aSrie * Continue to look for the first ELF object to determine the class of 34956e2cc86SAli Bahrami * objects to operate on. At the same time, look for the first archive 35056e2cc86SAli Bahrami * of ELF objects --- if no plain ELF object is specified, the type 35156e2cc86SAli Bahrami * of the first ELF object in the first archive will be used. If 35256e2cc86SAli Bahrami * there is no object, and no archive, then we fall back to a 32-bit 35356e2cc86SAli Bahrami * object for the native machine. 3547c478bd9Sstevel@tonic-gate */ 3557c478bd9Sstevel@tonic-gate for (; optind < argc; optind++) { 3567c478bd9Sstevel@tonic-gate int fd; 35756e2cc86SAli Bahrami FILE_HDR hdr; 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* 3607c478bd9Sstevel@tonic-gate * If we detect some more options return to getopt(). 3617c478bd9Sstevel@tonic-gate * Checking argv[optind][1] against null prevents a forever 3627c478bd9Sstevel@tonic-gate * loop if an unadorned `-' argument is passed to us. 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate if (argv[optind][0] == '-') { 3657c478bd9Sstevel@tonic-gate if (argv[optind][1] == '\0') 3667c478bd9Sstevel@tonic-gate continue; 3677c478bd9Sstevel@tonic-gate else 3687c478bd9Sstevel@tonic-gate goto getmore; 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717010c12aSrie /* 372ba2be530Sab196087 * If we've already determined the object class and 373ba2be530Sab196087 * machine type, continue to the next argument. Only 374ba2be530Sab196087 * the first object contributes to this decision, and 375ba2be530Sab196087 * there's no value to opening or examing the subsequent 376ba2be530Sab196087 * ones. We do need to keep going though, because there 377ba2be530Sab196087 * may be additional options that might affect our 378ba2be530Sab196087 * class/machine decision. 3797010c12aSrie */ 38056e2cc86SAli Bahrami if ((class != ELFCLASSNONE) && (mach32 != EM_NONE)) 3817010c12aSrie continue; 3827010c12aSrie 3837010c12aSrie /* 38456e2cc86SAli Bahrami * Open the file and determine if it is an object. We are 38556e2cc86SAli Bahrami * looking for ELF objects, or archives of ELF objects. 38656e2cc86SAli Bahrami * 38756e2cc86SAli Bahrami * Plain objects are simple, and are the common case, so 38856e2cc86SAli Bahrami * we examine them directly and avoid the map-unmap-map 38956e2cc86SAli Bahrami * that would occur if we used libelf. Archives are too 39056e2cc86SAli Bahrami * complex to be worth accessing directly, so if we identify 39156e2cc86SAli Bahrami * an archive, we use libelf on it and accept the cost. 3927010c12aSrie */ 3937c478bd9Sstevel@tonic-gate if ((fd = open(argv[optind], O_RDONLY)) == -1) { 3947c478bd9Sstevel@tonic-gate int err = errno; 3957c478bd9Sstevel@tonic-gate 3965aefb655Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 3977c478bd9Sstevel@tonic-gate argv[optind], strerror(err)); 3987010c12aSrie return (1); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 40156e2cc86SAli Bahrami if (pread(fd, &hdr, sizeof (hdr), 0) != sizeof (hdr)) { 40256e2cc86SAli Bahrami (void) close(fd); 40356e2cc86SAli Bahrami continue; 40456e2cc86SAli Bahrami } 40556e2cc86SAli Bahrami 40656e2cc86SAli Bahrami if ((hdr.ehdr.e_ident[EI_MAG0] == ELFMAG0) && 40756e2cc86SAli Bahrami (hdr.ehdr.e_ident[EI_MAG1] == ELFMAG1) && 40856e2cc86SAli Bahrami (hdr.ehdr.e_ident[EI_MAG2] == ELFMAG2) && 40956e2cc86SAli Bahrami (hdr.ehdr.e_ident[EI_MAG3] == ELFMAG3)) { 41056e2cc86SAli Bahrami if (class == ELFCLASSNONE) { 41156e2cc86SAli Bahrami class = hdr.ehdr.e_ident[EI_CLASS]; 41256e2cc86SAli Bahrami if ((class != ELFCLASS32) && 41356e2cc86SAli Bahrami (class != ELFCLASS64)) 41456e2cc86SAli Bahrami class = ELFCLASSNONE; 4157c478bd9Sstevel@tonic-gate } 416ba2be530Sab196087 417ba2be530Sab196087 if (mach32 == EM_NONE) { 418ba2be530Sab196087 int one = 1; 419ba2be530Sab196087 uchar_t *one_p = (uchar_t *)&one; 420ba2be530Sab196087 int ld_elfdata; 421ba2be530Sab196087 422ba2be530Sab196087 ld_elfdata = (one_p[0] == 1) ? 423ba2be530Sab196087 ELFDATA2LSB : ELFDATA2MSB; 424ba2be530Sab196087 /* 425ba2be530Sab196087 * Both the 32 and 64-bit versions get the 426ba2be530Sab196087 * type from the object. If the user has 427ba2be530Sab196087 * asked for an inconsistant class/machine 428ba2be530Sab196087 * combination, libld will catch it. 429ba2be530Sab196087 */ 430ba2be530Sab196087 mach32 = mach64 = 43156e2cc86SAli Bahrami (ld_elfdata == hdr.ehdr.e_ident[EI_DATA]) ? 43256e2cc86SAli Bahrami hdr.ehdr.e_machine : 43356e2cc86SAli Bahrami BSWAP_HALF(hdr.ehdr.e_machine); 434ba2be530Sab196087 } 43556e2cc86SAli Bahrami } else if (!ar_found && 43656e2cc86SAli Bahrami (memcmp(&hdr.armag, ARMAG, SARMAG) == 0)) { 43756e2cc86SAli Bahrami Elf *elf; 43856e2cc86SAli Bahrami 43956e2cc86SAli Bahrami (void) elf_version(EV_CURRENT); 44056e2cc86SAli Bahrami if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 44156e2cc86SAli Bahrami (void) close(fd); 44256e2cc86SAli Bahrami continue; 44356e2cc86SAli Bahrami } 44456e2cc86SAli Bahrami if (elf_kind(elf) == ELF_K_AR) 44556e2cc86SAli Bahrami ar_found = 44656e2cc86SAli Bahrami archive(fd, elf, &ar_class, &ar_mach); 44756e2cc86SAli Bahrami (void) elf_end(elf); 448ba2be530Sab196087 } 449ba2be530Sab196087 4507c478bd9Sstevel@tonic-gate (void) close(fd); 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate /* 45456e2cc86SAli Bahrami * ELFCLASS of output object: If we did not establish a class from a 45556e2cc86SAli Bahrami * command option, or from the first plain object, then use the class 45656e2cc86SAli Bahrami * from the first archive, and failing that, default to 32-bit. 4577c478bd9Sstevel@tonic-gate */ 45856e2cc86SAli Bahrami if (class == ELFCLASSNONE) 45956e2cc86SAli Bahrami class = ar_found ? ar_class : ELFCLASS32; 46056e2cc86SAli Bahrami *class_ret = class; 461ba2be530Sab196087 46256e2cc86SAli Bahrami /* ELFCLASS of link-editor to use */ 46356e2cc86SAli Bahrami *ldclass_ret = ldclass; 464ba2be530Sab196087 465ba2be530Sab196087 /* 46656e2cc86SAli Bahrami * Machine type of output object: If we did not establish a machine 46756e2cc86SAli Bahrami * type from the command line, or from the first plain object, then 46856e2cc86SAli Bahrami * use the machine established by the first archive, and failing that, 46956e2cc86SAli Bahrami * use the native machine. 470ba2be530Sab196087 */ 47156e2cc86SAli Bahrami *mach = (class == ELFCLASS64) ? mach64 : mach32; 472ba2be530Sab196087 if (*mach == EM_NONE) 47356e2cc86SAli Bahrami if (ar_found) 47456e2cc86SAli Bahrami *mach = ar_mach; 47556e2cc86SAli Bahrami else 47656e2cc86SAli Bahrami *mach = (class == ELFCLASS64) ? M_MACH_64 : M_MACH_32; 477ba2be530Sab196087 4787010c12aSrie return (0); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate /* 48292a02081SRod Evans * Process an LD_OPTIONS environment string. This routine is first called to 48392a02081SRod Evans * count the number of options, and second to initialize a new argument array 48492a02081SRod Evans * with each option. 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate static int 48792a02081SRod Evans process_ldoptions(char *str, char **nargv) 4887c478bd9Sstevel@tonic-gate { 48992a02081SRod Evans int argc = 0; 49092a02081SRod Evans char *arg = str; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate /* 49392a02081SRod Evans * Walk the environment string processing any arguments that are 49492a02081SRod Evans * separated by white space. 49592a02081SRod Evans */ 49692a02081SRod Evans while (*str != '\0') { 49792a02081SRod Evans if (isspace(*str)) { 49892a02081SRod Evans /* 49992a02081SRod Evans * If a new argument array has been provided, terminate 50092a02081SRod Evans * the original environment string, and initialize the 50192a02081SRod Evans * appropriate argument array entry. 50292a02081SRod Evans */ 50392a02081SRod Evans if (nargv) { 50492a02081SRod Evans *str++ = '\0'; 50592a02081SRod Evans nargv[argc] = arg; 50692a02081SRod Evans } 50792a02081SRod Evans 50892a02081SRod Evans argc++; 50992a02081SRod Evans while (isspace(*str)) 51092a02081SRod Evans str++; 51192a02081SRod Evans arg = str; 51292a02081SRod Evans } else 51392a02081SRod Evans str++; 51492a02081SRod Evans } 51592a02081SRod Evans if (arg != str) { 51692a02081SRod Evans /* 51792a02081SRod Evans * If a new argument array has been provided, initialize the 51892a02081SRod Evans * final argument array entry. 51992a02081SRod Evans */ 52092a02081SRod Evans if (nargv) 52192a02081SRod Evans nargv[argc] = arg; 52292a02081SRod Evans argc++; 52392a02081SRod Evans } 52492a02081SRod Evans 52592a02081SRod Evans return (argc); 52692a02081SRod Evans } 52792a02081SRod Evans 52892a02081SRod Evans /* 52992a02081SRod Evans * Determine whether an LD_OPTIONS environment variable is set, and if so, 53092a02081SRod Evans * prepend environment string as a series of options to the argv array. 53192a02081SRod Evans */ 53292a02081SRod Evans static int 53392a02081SRod Evans prepend_ldoptions(int *argcp, char ***argvp) 53492a02081SRod Evans { 53592a02081SRod Evans int nargc; 53692a02081SRod Evans char **nargv, *ld_options; 53792a02081SRod Evans int err, count; 53892a02081SRod Evans 53992a02081SRod Evans if ((ld_options = getenv(MSG_ORIG(MSG_LD_OPTIONS))) == NULL) 54092a02081SRod Evans return (0); 54192a02081SRod Evans 54292a02081SRod Evans /* 543635216b6SRod Evans * Get rid of any leading white space, and make sure the environment 544635216b6SRod Evans * string has size. 545635216b6SRod Evans */ 546635216b6SRod Evans while (isspace(*ld_options)) 547635216b6SRod Evans ld_options++; 54898c080d5SRod Evans if (ld_options[0] == '\0') 549635216b6SRod Evans return (0); 550635216b6SRod Evans 551635216b6SRod Evans /* 55292a02081SRod Evans * Prevent modification of actual environment strings. 55392a02081SRod Evans */ 55492a02081SRod Evans if ((ld_options = strdup(ld_options)) == NULL) { 55592a02081SRod Evans err = errno; 55692a02081SRod Evans eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_ALLOC), strerror(err)); 55792a02081SRod Evans return (1); 55892a02081SRod Evans } 55992a02081SRod Evans 56092a02081SRod Evans /* 56192a02081SRod Evans * Determine the number of options provided. 5627c478bd9Sstevel@tonic-gate */ 56392a02081SRod Evans nargc = process_ldoptions(ld_options, NULL); 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate /* 5667c478bd9Sstevel@tonic-gate * Allocate a new argv array big enough to hold the new options from 5677c478bd9Sstevel@tonic-gate * the environment string and the old argv options. 5687c478bd9Sstevel@tonic-gate */ 56992a02081SRod Evans if ((nargv = malloc((nargc + *argcp + 1) * sizeof (char *))) == NULL) { 57092a02081SRod Evans err = errno; 5715aefb655Srie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_ALLOC), strerror(err)); 57292a02081SRod Evans return (1); 5735aefb655Srie } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate /* 5767c478bd9Sstevel@tonic-gate * Initialize first element of new argv array to be the first element 5777c478bd9Sstevel@tonic-gate * of the old argv array (ie. calling programs name). Then add the new 5787c478bd9Sstevel@tonic-gate * args obtained from the environment. 5797c478bd9Sstevel@tonic-gate */ 5807c478bd9Sstevel@tonic-gate nargc = 0; 58192a02081SRod Evans nargv[nargc++] = (*argvp)[0]; 58292a02081SRod Evans nargc += process_ldoptions(ld_options, &nargv[nargc]); 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate /* 5857c478bd9Sstevel@tonic-gate * Now add the original argv array (skipping argv[0]) to the end of the 58692a02081SRod Evans * new argv array, and re-vector argc and argv to reference this new 58792a02081SRod Evans * array 5887c478bd9Sstevel@tonic-gate */ 58992a02081SRod Evans for (count = 1; count < *argcp; count++, nargc++) 5907c478bd9Sstevel@tonic-gate nargv[nargc] = (*argvp)[count]; 59192a02081SRod Evans 59292a02081SRod Evans nargv[nargc] = NULL; 59392a02081SRod Evans 59492a02081SRod Evans *argcp = nargc; 5957c478bd9Sstevel@tonic-gate *argvp = nargv; 5967c478bd9Sstevel@tonic-gate 59792a02081SRod Evans return (0); 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* 6015aefb655Srie * Check to see if there is a LD_ALTEXEC=<path to alternate ld> in the 6025aefb655Srie * environment. If so, first null the environment variable out, and then 6035aefb655Srie * exec() the binary pointed to by the environment variable, passing the same 6045aefb655Srie * arguments as the originating process. This mechanism permits using 6055aefb655Srie * alternate link-editors (debugging/developer copies) even in complex build 6065aefb655Srie * environments. 6077c478bd9Sstevel@tonic-gate */ 6087010c12aSrie static int 6097c478bd9Sstevel@tonic-gate ld_altexec(char **argv, char **envp) 6107c478bd9Sstevel@tonic-gate { 6117c478bd9Sstevel@tonic-gate char *execstr; 6127c478bd9Sstevel@tonic-gate char **str; 6137010c12aSrie int err; 6147010c12aSrie 6157c478bd9Sstevel@tonic-gate for (str = envp; *str; str++) { 6167c478bd9Sstevel@tonic-gate if (strncmp(*str, MSG_ORIG(MSG_LD_ALTEXEC), 6177c478bd9Sstevel@tonic-gate MSG_LD_ALTEXEC_SIZE) == 0) { 6187c478bd9Sstevel@tonic-gate break; 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate /* 6237010c12aSrie * If LD_ALTEXEC isn't set, return to continue executing the present 6247010c12aSrie * link-editor. 6257010c12aSrie */ 6267010c12aSrie if (*str == 0) 6277010c12aSrie return (0); 6287010c12aSrie 6297010c12aSrie /* 6307010c12aSrie * Get a pointer to the actual string. If it's a null entry, return. 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate execstr = strdup(*str + MSG_LD_ALTEXEC_SIZE); 6337c478bd9Sstevel@tonic-gate if (*execstr == '\0') 6347010c12aSrie return (0); 6357010c12aSrie 6367c478bd9Sstevel@tonic-gate /* 6377c478bd9Sstevel@tonic-gate * Null out the LD_ALTEXEC= environment entry. 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate (*str)[MSG_LD_ALTEXEC_SIZE] = '\0'; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate /* 6427c478bd9Sstevel@tonic-gate * Set argv[0] to point to our new linker 6437c478bd9Sstevel@tonic-gate */ 6447c478bd9Sstevel@tonic-gate argv[0] = execstr; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* 6477c478bd9Sstevel@tonic-gate * And attempt to execute it. 6487c478bd9Sstevel@tonic-gate */ 6497c478bd9Sstevel@tonic-gate (void) execve(execstr, argv, envp); 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate /* 6527010c12aSrie * If the exec() fails, return a failure indication. 6537c478bd9Sstevel@tonic-gate */ 6547010c12aSrie err = errno; 6557010c12aSrie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_EXEC), execstr, 6567010c12aSrie strerror(err)); 6577010c12aSrie return (1); 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate int 6617c478bd9Sstevel@tonic-gate main(int argc, char **argv, char **envp) 6627c478bd9Sstevel@tonic-gate { 66392a02081SRod Evans char **oargv = argv; 66456e2cc86SAli Bahrami uchar_t class, ldclass, checkclass; 665ba2be530Sab196087 Half mach; 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* 6687c478bd9Sstevel@tonic-gate * Establish locale. 6697c478bd9Sstevel@tonic-gate */ 6707c478bd9Sstevel@tonic-gate (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 6717c478bd9Sstevel@tonic-gate (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate /* 6747010c12aSrie * Execute an alternate linker if the LD_ALTEXEC environment variable is 6757010c12aSrie * set. If a specified alternative could not be found, bail. 6767c478bd9Sstevel@tonic-gate */ 6777010c12aSrie if (ld_altexec(argv, envp)) 6787010c12aSrie return (1); 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /* 6817c478bd9Sstevel@tonic-gate * Check the LD_OPTIONS environment variable, and if present prepend 6827c478bd9Sstevel@tonic-gate * the arguments specified to the command line argument list. 6837c478bd9Sstevel@tonic-gate */ 68492a02081SRod Evans if (prepend_ldoptions(&argc, &argv)) 6857c478bd9Sstevel@tonic-gate return (1); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 688ba2be530Sab196087 * Examine the command arguments to determine: 689ba2be530Sab196087 * - object class 690ba2be530Sab196087 * - link-editor class 691ba2be530Sab196087 * - target machine 6927c478bd9Sstevel@tonic-gate */ 69356e2cc86SAli Bahrami if (process_args(argc, argv, &class, &ldclass, &mach)) 6947c478bd9Sstevel@tonic-gate return (1); 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate /* 69756e2cc86SAli Bahrami * Unless a 32-bit link-editor was explicitly requested, try 69856e2cc86SAli Bahrami * to exec the 64-bit version. 6997c478bd9Sstevel@tonic-gate */ 70056e2cc86SAli Bahrami if (ldclass != ELFCLASS32) 7017010c12aSrie checkclass = conv_check_native(oargv, envp); 7027010c12aSrie 70356e2cc86SAli Bahrami /* 70456e2cc86SAli Bahrami * If an attempt to exec the 64-bit link-editor fails: 70556e2cc86SAli Bahrami * - Bail if the 64-bit linker was explicitly requested 70656e2cc86SAli Bahrami * - Continue quietly if the 64-bit linker was not requested. 70756e2cc86SAli Bahrami * This is undoubtedly due to hardware/kernel limitations, 70856e2cc86SAli Bahrami * and therefore represents the best we can do. Note that 70956e2cc86SAli Bahrami * the 32-bit linker is capable of linking anything the 71056e2cc86SAli Bahrami * 64-bit version is, subject to a 4GB limit on memory, and 71156e2cc86SAli Bahrami * 2GB object size. 71256e2cc86SAli Bahrami */ 7137010c12aSrie if ((ldclass == ELFCLASS64) && (checkclass != ELFCLASS64)) { 7147010c12aSrie eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_64)); 7157010c12aSrie return (1); 7167010c12aSrie } 7177c478bd9Sstevel@tonic-gate 71856e2cc86SAli Bahrami /* Call the libld entry point for the specified ELFCLASS */ 71956e2cc86SAli Bahrami if (class == ELFCLASS64) 720ba2be530Sab196087 return (ld64_main(argc, argv, mach)); 7215aefb655Srie else 722ba2be530Sab196087 return (ld32_main(argc, argv, mach)); 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate /* 72656e2cc86SAli Bahrami * We supply this function for the msg module 7277c478bd9Sstevel@tonic-gate */ 7287c478bd9Sstevel@tonic-gate const char * 7297c478bd9Sstevel@tonic-gate _ld_msg(Msg mid) 7307c478bd9Sstevel@tonic-gate { 7317c478bd9Sstevel@tonic-gate return (gettext(MSG_ORIG(mid))); 7327c478bd9Sstevel@tonic-gate } 733