1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <stdio.h> 30*0Sstevel@tonic-gate #include <stdlib.h> 31*0Sstevel@tonic-gate #include <unistd.h> 32*0Sstevel@tonic-gate #include <stdarg.h> 33*0Sstevel@tonic-gate #include <string.h> 34*0Sstevel@tonic-gate #include <errno.h> 35*0Sstevel@tonic-gate #include <fcntl.h> 36*0Sstevel@tonic-gate #include <libintl.h> 37*0Sstevel@tonic-gate #include <locale.h> 38*0Sstevel@tonic-gate #include <fcntl.h> 39*0Sstevel@tonic-gate #include <dlfcn.h> 40*0Sstevel@tonic-gate #include "conv.h" 41*0Sstevel@tonic-gate #include "libld.h" 42*0Sstevel@tonic-gate #include "msg.h" 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate /* 46*0Sstevel@tonic-gate * The following prevent us from having to include ctype.h which defines these 47*0Sstevel@tonic-gate * functions as macros which reference the __ctype[] array. Go through .plt's 48*0Sstevel@tonic-gate * to get to these functions in libc rather than have every invocation of ld 49*0Sstevel@tonic-gate * have to suffer the R_SPARC_COPY overhead of the __ctype[] array. 50*0Sstevel@tonic-gate */ 51*0Sstevel@tonic-gate extern int isspace(int); 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate /* 55*0Sstevel@tonic-gate * Determine whether we need the Elf32 or Elf64 libld. 56*0Sstevel@tonic-gate */ 57*0Sstevel@tonic-gate static int 58*0Sstevel@tonic-gate determine_class(int argc, char ** argv) 59*0Sstevel@tonic-gate { 60*0Sstevel@tonic-gate unsigned char class = 0; 61*0Sstevel@tonic-gate int c; 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate getmore: 64*0Sstevel@tonic-gate /* 65*0Sstevel@tonic-gate * Skip options. 66*0Sstevel@tonic-gate * 67*0Sstevel@tonic-gate * The only option we're interested in is -64, which enforces a 64-bit 68*0Sstevel@tonic-gate * link-edit. This option is used when the only input to ld() is a 69*0Sstevel@tonic-gate * mapfile and a 64-bit object is required. If we've already processed 70*0Sstevel@tonic-gate * a 32-bit object and we find -64, we have an error condition, but let 71*0Sstevel@tonic-gate * this fall through to libld to obtain the default error message. 72*0Sstevel@tonic-gate */ 73*0Sstevel@tonic-gate opterr = 0; 74*0Sstevel@tonic-gate while ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) { 75*0Sstevel@tonic-gate switch (c) { 76*0Sstevel@tonic-gate case '6': 77*0Sstevel@tonic-gate return (ELFCLASS64); 78*0Sstevel@tonic-gate default: 79*0Sstevel@tonic-gate break; 80*0Sstevel@tonic-gate } 81*0Sstevel@tonic-gate } 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate /* 84*0Sstevel@tonic-gate * Otherwise look for the first ELF object to determine the class of 85*0Sstevel@tonic-gate * objects to operate on. 86*0Sstevel@tonic-gate */ 87*0Sstevel@tonic-gate for (; optind < argc; optind++) { 88*0Sstevel@tonic-gate int fd; 89*0Sstevel@tonic-gate unsigned char ident[EI_NIDENT]; 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate /* 92*0Sstevel@tonic-gate * If we've already analyzed the initial object, continue. 93*0Sstevel@tonic-gate * We're only interested in skipping all files to check for 94*0Sstevel@tonic-gate * more options, and specifically if the -64 option is set. 95*0Sstevel@tonic-gate */ 96*0Sstevel@tonic-gate if (class) 97*0Sstevel@tonic-gate continue; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate /* 100*0Sstevel@tonic-gate * If we detect some more options return to getopt(). 101*0Sstevel@tonic-gate * Checking argv[optind][1] against null prevents a forever 102*0Sstevel@tonic-gate * loop if an unadorned `-' argument is passed to us. 103*0Sstevel@tonic-gate */ 104*0Sstevel@tonic-gate if (argv[optind][0] == '-') { 105*0Sstevel@tonic-gate if (argv[optind][1] == '\0') 106*0Sstevel@tonic-gate continue; 107*0Sstevel@tonic-gate else 108*0Sstevel@tonic-gate goto getmore; 109*0Sstevel@tonic-gate } 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate if ((fd = open(argv[optind], O_RDONLY)) == -1) { 112*0Sstevel@tonic-gate int err = errno; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 115*0Sstevel@tonic-gate argv[optind], strerror(err)); 116*0Sstevel@tonic-gate return (0); 117*0Sstevel@tonic-gate } 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate /* 120*0Sstevel@tonic-gate * Determine the files ELF class. 121*0Sstevel@tonic-gate */ 122*0Sstevel@tonic-gate if ((read(fd, ident, EI_NIDENT) == EI_NIDENT) && 123*0Sstevel@tonic-gate (ident[EI_MAG0] == ELFMAG0) && 124*0Sstevel@tonic-gate (ident[EI_MAG1] == ELFMAG1) && 125*0Sstevel@tonic-gate (ident[EI_MAG2] == ELFMAG2) && 126*0Sstevel@tonic-gate (ident[EI_MAG3] == ELFMAG3)) { 127*0Sstevel@tonic-gate if (((class = ident[EI_CLASS]) != ELFCLASS32) && 128*0Sstevel@tonic-gate (class != ELFCLASS64)) 129*0Sstevel@tonic-gate class = 0; 130*0Sstevel@tonic-gate } 131*0Sstevel@tonic-gate (void) close(fd); 132*0Sstevel@tonic-gate } 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate /* 135*0Sstevel@tonic-gate * If we couldn't establish a class default to 32-bit. 136*0Sstevel@tonic-gate */ 137*0Sstevel@tonic-gate if (class) 138*0Sstevel@tonic-gate return (class); 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate return (ELFCLASS32); 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate /* 144*0Sstevel@tonic-gate * Prepend environment string as a series of options to the argv array. 145*0Sstevel@tonic-gate */ 146*0Sstevel@tonic-gate static int 147*0Sstevel@tonic-gate prepend_ldoptions(char *ld_options, int *argcp, char ***argvp) 148*0Sstevel@tonic-gate { 149*0Sstevel@tonic-gate int nargc; /* New argc */ 150*0Sstevel@tonic-gate char **nargv; /* New argv */ 151*0Sstevel@tonic-gate char *arg, *string; 152*0Sstevel@tonic-gate int count; 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate /* 155*0Sstevel@tonic-gate * Get rid of leading white space, and make sure the string has size. 156*0Sstevel@tonic-gate */ 157*0Sstevel@tonic-gate while (isspace(*ld_options)) 158*0Sstevel@tonic-gate ld_options++; 159*0Sstevel@tonic-gate if (*ld_options == '\0') 160*0Sstevel@tonic-gate return (1); 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate nargc = 0; 163*0Sstevel@tonic-gate arg = string = ld_options; 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate /* 166*0Sstevel@tonic-gate * Walk the environment string counting any arguments that are 167*0Sstevel@tonic-gate * separated by white space. 168*0Sstevel@tonic-gate */ 169*0Sstevel@tonic-gate while (*string != '\0') { 170*0Sstevel@tonic-gate if (isspace(*string)) { 171*0Sstevel@tonic-gate nargc++; 172*0Sstevel@tonic-gate while (isspace(*string)) 173*0Sstevel@tonic-gate string++; 174*0Sstevel@tonic-gate arg = string; 175*0Sstevel@tonic-gate } else 176*0Sstevel@tonic-gate string++; 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate if (arg != string) 179*0Sstevel@tonic-gate nargc++; 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate /* 182*0Sstevel@tonic-gate * Allocate a new argv array big enough to hold the new options from 183*0Sstevel@tonic-gate * the environment string and the old argv options. 184*0Sstevel@tonic-gate */ 185*0Sstevel@tonic-gate if ((nargv = calloc(nargc + *argcp, sizeof (char *))) == 0) 186*0Sstevel@tonic-gate return (0); 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate /* 189*0Sstevel@tonic-gate * Initialize first element of new argv array to be the first element 190*0Sstevel@tonic-gate * of the old argv array (ie. calling programs name). Then add the new 191*0Sstevel@tonic-gate * args obtained from the environment. 192*0Sstevel@tonic-gate */ 193*0Sstevel@tonic-gate nargv[0] = (*argvp)[0]; 194*0Sstevel@tonic-gate nargc = 0; 195*0Sstevel@tonic-gate arg = string = ld_options; 196*0Sstevel@tonic-gate while (*string != '\0') { 197*0Sstevel@tonic-gate if (isspace(*string)) { 198*0Sstevel@tonic-gate nargc++; 199*0Sstevel@tonic-gate *string++ = '\0'; 200*0Sstevel@tonic-gate nargv[nargc] = arg; 201*0Sstevel@tonic-gate while (isspace(*string)) 202*0Sstevel@tonic-gate string++; 203*0Sstevel@tonic-gate arg = string; 204*0Sstevel@tonic-gate } else 205*0Sstevel@tonic-gate string++; 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate if (arg != string) { 208*0Sstevel@tonic-gate nargc++; 209*0Sstevel@tonic-gate nargv[nargc] = arg; 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate /* 213*0Sstevel@tonic-gate * Now add the original argv array (skipping argv[0]) to the end of the 214*0Sstevel@tonic-gate * new argv array, and overwrite the old argc and argv. 215*0Sstevel@tonic-gate */ 216*0Sstevel@tonic-gate for (count = 1; count < *argcp; count++) { 217*0Sstevel@tonic-gate nargc++; 218*0Sstevel@tonic-gate nargv[nargc] = (*argvp)[count]; 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate *argcp = ++nargc; 221*0Sstevel@tonic-gate *argvp = nargv; 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate return (1); 224*0Sstevel@tonic-gate } 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate /* 227*0Sstevel@tonic-gate * The ld_altexec() function checks to see if there is 228*0Sstevel@tonic-gate * a LD_ALTEXEC=<path to alternate ld> in the environment. 229*0Sstevel@tonic-gate * If there is - it will null that variable out - and then 230*0Sstevel@tonic-gate * exec() the binary pointed to with the same arguements 231*0Sstevel@tonic-gate * as the originating process. 232*0Sstevel@tonic-gate * This permits using alternate link-editors (debugging/developer 233*0Sstevel@tonic-gate * copies) even in complex build environments. 234*0Sstevel@tonic-gate * 235*0Sstevel@tonic-gate * If LD_ALTEXEC= isn't set, or the exec() fails this 236*0Sstevel@tonic-gate * function silently returns and the execution of this 237*0Sstevel@tonic-gate * link-editor continues on. 238*0Sstevel@tonic-gate */ 239*0Sstevel@tonic-gate void 240*0Sstevel@tonic-gate ld_altexec(char **argv, char **envp) 241*0Sstevel@tonic-gate { 242*0Sstevel@tonic-gate char *execstr; 243*0Sstevel@tonic-gate char **str; 244*0Sstevel@tonic-gate for (str = envp; *str; str++) { 245*0Sstevel@tonic-gate if (strncmp(*str, MSG_ORIG(MSG_LD_ALTEXEC), 246*0Sstevel@tonic-gate MSG_LD_ALTEXEC_SIZE) == 0) { 247*0Sstevel@tonic-gate break; 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate if (*str == 0) 251*0Sstevel@tonic-gate return; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate /* 254*0Sstevel@tonic-gate * get a pointer to the actual string - if it's 255*0Sstevel@tonic-gate * a null entry - we return. 256*0Sstevel@tonic-gate */ 257*0Sstevel@tonic-gate execstr = strdup(*str + MSG_LD_ALTEXEC_SIZE); 258*0Sstevel@tonic-gate if (*execstr == '\0') 259*0Sstevel@tonic-gate return; 260*0Sstevel@tonic-gate /* 261*0Sstevel@tonic-gate * Null out the LD_ALTEXEC= environment entry. 262*0Sstevel@tonic-gate */ 263*0Sstevel@tonic-gate (*str)[MSG_LD_ALTEXEC_SIZE] = '\0'; 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate /* 266*0Sstevel@tonic-gate * Set argv[0] to point to our new linker 267*0Sstevel@tonic-gate */ 268*0Sstevel@tonic-gate argv[0] = execstr; 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate /* 271*0Sstevel@tonic-gate * And attempt to execute it. 272*0Sstevel@tonic-gate */ 273*0Sstevel@tonic-gate (void) execve(execstr, argv, envp); 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate /* 276*0Sstevel@tonic-gate * If the exec failes - we just silently fall 277*0Sstevel@tonic-gate * through and continue execution of the 278*0Sstevel@tonic-gate * current link-editor. 279*0Sstevel@tonic-gate */ 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate int 283*0Sstevel@tonic-gate main(int argc, char **argv, char **envp) 284*0Sstevel@tonic-gate { 285*0Sstevel@tonic-gate char *ld_options, **oargv = argv; 286*0Sstevel@tonic-gate const char *libld = MSG_ORIG(MSG_LD_LIB32); 287*0Sstevel@tonic-gate void *libld_h; 288*0Sstevel@tonic-gate int (*libld_main)(int, char **); 289*0Sstevel@tonic-gate unsigned char class; 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate /* 292*0Sstevel@tonic-gate * XX64 -- Strip "-Wl," from the head of each argument. 293*0Sstevel@tonic-gate * This is to accommodate awkwardness in pasing ld arguments 294*0Sstevel@tonic-gate * to gcc while maintaining the structure of the build 295*0Sstevel@tonic-gate * environment's Makefiles. 296*0Sstevel@tonic-gate */ 297*0Sstevel@tonic-gate { 298*0Sstevel@tonic-gate int i; 299*0Sstevel@tonic-gate char *p; 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate for (i = 0; i < argc; i++) { 302*0Sstevel@tonic-gate p = argv[i]; 303*0Sstevel@tonic-gate while (*(p + 1) == 'W' && strncmp(p, "-Wl,-", 5) == 0) 304*0Sstevel@tonic-gate argv[i] = (p += 4); 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate /* 309*0Sstevel@tonic-gate * Establish locale. 310*0Sstevel@tonic-gate */ 311*0Sstevel@tonic-gate (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 312*0Sstevel@tonic-gate (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate /* 315*0Sstevel@tonic-gate * Execute alternate linker if LD_ALTEXEC environment variable is set. 316*0Sstevel@tonic-gate */ 317*0Sstevel@tonic-gate ld_altexec(argv, envp); 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate /* 320*0Sstevel@tonic-gate * Check the LD_OPTIONS environment variable, and if present prepend 321*0Sstevel@tonic-gate * the arguments specified to the command line argument list. 322*0Sstevel@tonic-gate */ 323*0Sstevel@tonic-gate if ((ld_options = getenv(MSG_ORIG(MSG_LD_OPTIONS))) != NULL) { 324*0Sstevel@tonic-gate /* 325*0Sstevel@tonic-gate * Prevent modification of actual environment strings. 326*0Sstevel@tonic-gate */ 327*0Sstevel@tonic-gate if (((ld_options = strdup(ld_options)) == NULL) || 328*0Sstevel@tonic-gate (prepend_ldoptions(ld_options, &argc, &argv) == 0)) 329*0Sstevel@tonic-gate return (1); 330*0Sstevel@tonic-gate } 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate /* 333*0Sstevel@tonic-gate * Locate the first input file and from it determine the class of 334*0Sstevel@tonic-gate * objects we're going to process. If the class is ELFCLASS64 we'll 335*0Sstevel@tonic-gate * specifically load libld.so.3, otherwise we'll fall back to 336*0Sstevel@tonic-gate * libld.so.2. Note that if the option -64 is encountered a 64-bit 337*0Sstevel@tonic-gate * link is explicitly being requested. 338*0Sstevel@tonic-gate */ 339*0Sstevel@tonic-gate if ((class = determine_class(argc, argv)) == 0) 340*0Sstevel@tonic-gate return (1); 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate /* 343*0Sstevel@tonic-gate * dlopen() right libld implementation. Note: the RTLD_GLOBAL flag is 344*0Sstevel@tonic-gate * added to make ld behave as if libld was one of its dependencies. 345*0Sstevel@tonic-gate * Support libraries, like libldstab.so.1, may expect this, to get at 346*0Sstevel@tonic-gate * libld_malloc, which they argueably shouldn't be using anyway. 347*0Sstevel@tonic-gate */ 348*0Sstevel@tonic-gate if (class == ELFCLASS64) { 349*0Sstevel@tonic-gate /* 350*0Sstevel@tonic-gate * If we're on a 64-bit kernel, try to exec a full 64-bit 351*0Sstevel@tonic-gate * version of ld. 352*0Sstevel@tonic-gate */ 353*0Sstevel@tonic-gate conv_check_native(oargv, envp); 354*0Sstevel@tonic-gate libld = MSG_ORIG(MSG_LD_LIB64); 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate if ((libld_h = dlopen(libld, (RTLD_LAZY | RTLD_GLOBAL))) == NULL) { 357*0Sstevel@tonic-gate eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_DLOPEN), libld, dlerror()); 358*0Sstevel@tonic-gate return (1); 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate /* 362*0Sstevel@tonic-gate * Find ld_main(), which is ld's generic entry point. 363*0Sstevel@tonic-gate */ 364*0Sstevel@tonic-gate if ((libld_main = (int (*)(int, char **))dlsym(libld_h, 365*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_MAIN))) == NULL) { 366*0Sstevel@tonic-gate eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_DLSYM), libld, dlerror()); 367*0Sstevel@tonic-gate return (1); 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate /* 371*0Sstevel@tonic-gate * Reset the arg counter and getopt(3c) error message flag and call the 372*0Sstevel@tonic-gate * generic entry point. 373*0Sstevel@tonic-gate */ 374*0Sstevel@tonic-gate optind = opterr = 1; 375*0Sstevel@tonic-gate return (libld_main(argc, argv)); 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate /* 380*0Sstevel@tonic-gate * Exported interfaces required by our dependencies. libld and friends bind to 381*0Sstevel@tonic-gate * the different implementations of these provided by either ld or ld.so.1. 382*0Sstevel@tonic-gate */ 383*0Sstevel@tonic-gate const char * 384*0Sstevel@tonic-gate _ld_msg(Msg mid) 385*0Sstevel@tonic-gate { 386*0Sstevel@tonic-gate return (gettext(MSG_ORIG(mid))); 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate /* 390*0Sstevel@tonic-gate * Print a message to stdout 391*0Sstevel@tonic-gate */ 392*0Sstevel@tonic-gate /* VARARGS2 */ 393*0Sstevel@tonic-gate void 394*0Sstevel@tonic-gate eprintf(Error error, const char *format, ...) 395*0Sstevel@tonic-gate { 396*0Sstevel@tonic-gate va_list args; 397*0Sstevel@tonic-gate static const char *strings[ERR_NUM] = { MSG_ORIG(MSG_STR_EMPTY) }; 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate if (error > ERR_NONE) { 400*0Sstevel@tonic-gate if (error == ERR_WARNING) { 401*0Sstevel@tonic-gate if (strings[ERR_WARNING] == 0) 402*0Sstevel@tonic-gate strings[ERR_WARNING] = MSG_INTL(MSG_ERR_WARNING); 403*0Sstevel@tonic-gate } else if (error == ERR_FATAL) { 404*0Sstevel@tonic-gate if (strings[ERR_FATAL] == 0) 405*0Sstevel@tonic-gate strings[ERR_FATAL] = MSG_INTL(MSG_ERR_FATAL); 406*0Sstevel@tonic-gate } else if (error == ERR_ELF) { 407*0Sstevel@tonic-gate if (strings[ERR_ELF] == 0) 408*0Sstevel@tonic-gate strings[ERR_ELF] = MSG_INTL(MSG_ERR_ELF); 409*0Sstevel@tonic-gate } 410*0Sstevel@tonic-gate (void) fputs(MSG_ORIG(MSG_STR_LDDIAG), stderr); 411*0Sstevel@tonic-gate } 412*0Sstevel@tonic-gate (void) fputs(strings[error], stderr); 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate va_start(args, format); 415*0Sstevel@tonic-gate (void) vfprintf(stderr, format, args); 416*0Sstevel@tonic-gate if (error == ERR_ELF) { 417*0Sstevel@tonic-gate int elferr; 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate if ((elferr = elf_errno()) != 0) 420*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_STR_ELFDIAG), 421*0Sstevel@tonic-gate elf_errmsg(elferr)); 422*0Sstevel@tonic-gate } 423*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_STR_NL)); 424*0Sstevel@tonic-gate (void) fflush(stderr); 425*0Sstevel@tonic-gate va_end(args); 426*0Sstevel@tonic-gate } 427