1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  *      Copyright (c) 1988 AT&T
  28  *        All Rights Reserved
  29  */
  30 
  31 /*
  32  * Utility functions
  33  */
  34 #include <unistd.h>
  35 #include <stdio.h>
  36 #include <stdarg.h>
  37 #include <string.h>
  38 #include <fcntl.h>
  39 #include <sys/types.h>
  40 #include <sys/mman.h>
  41 #include <errno.h>
  42 #include <sgs.h>
  43 #include <libintl.h>
  44 #include <debug.h>
  45 #include "msg.h"
  46 #include "_libld.h"
  47 
  48 /*
  49  * libld_malloc() and dz_map() are used for both performance and for ease of
  50  * programming:
  51  *
  52  * Performance:
  53  *      The link-edit is a short lived process which doesn't really free much
  54  *      of the dynamic memory that it requests.  Because of this, it is more
  55  *      important to optimize for quick memory allocations than the
  56  *      re-usability of the memory.
  57  *
  58  *      By also mmaping blocks of pages in from /dev/zero we don't need to
  59  *      waste the overhead of zeroing out these pages for calloc() requests.
  60  *
  61  * Memory Management:
  62  *      By doing all libld memory management through the ld_malloc routine
  63  *      it's much easier to free up all memory at the end by simply unmaping
  64  *      all of the blocks that were mapped in through dz_map().  This is much
  65  *      simpler then trying to track all of the libld structures that were
  66  *      dynamically allocate and are actually pointers into the ELF files.
  67  *
  68  *      It's important that we can free up all of our dynamic memory because
  69  *      libld is used by ld.so.1 when it performs dlopen()'s of relocatable
  70  *      objects.
  71  *
  72  * Format:
  73  *      The memory blocks for each allocation store the size of the allocation
  74  *      in the first 8 bytes of the block.  The pointer that is returned by
  75  *      libld_malloc() is actually the address of (block + 8):
  76  *
  77  *              (addr - 8)      block_size
  78  *              (addr)          <allocated block>
  79  *
  80  *      The size is retained in order to implement realloc(), and to perform
  81  *      the required memcpy().  8 bytes are uses, as the memory area returned
  82  *      by libld_malloc() must be 8 byte-aligned.  Even in a 32-bit environment,
  83  *      u_longlog_t pointers are employed.
  84  *
  85  * Map anonymous memory via MAP_ANON (added in Solaris 8).
  86  */
  87 static void *
  88 dz_map(size_t size)
  89 {
  90         void    *addr;
  91 
  92         if ((addr = mmap(0, size, (PROT_READ | PROT_WRITE | PROT_EXEC),
  93             (MAP_PRIVATE | MAP_ANON), -1, 0)) == MAP_FAILED) {
  94                 int     err = errno;
  95                 eprintf(NULL, ERR_FATAL, MSG_INTL(MSG_SYS_MMAPANON),
  96                     strerror(err));
  97                 return (MAP_FAILED);
  98         }
  99         return (addr);
 100 }
 101 
 102 void *
 103 libld_malloc(size_t size)
 104 {
 105         Ld_heap         *chp = ld_heap;
 106         void            *vptr;
 107         size_t          asize = size + HEAPALIGN;
 108 
 109         /*
 110          * If this is the first allocation, or the allocation request is greater
 111          * than the current free space available, allocate a new heap.
 112          */
 113         if ((chp == NULL) ||
 114             (((size_t)chp->lh_end - (size_t)chp->lh_free) <= asize)) {
 115                 Ld_heap *nhp;
 116                 size_t  hsize = (size_t)S_ROUND(sizeof (Ld_heap), HEAPALIGN);
 117                 size_t  tsize = (size_t)S_ROUND((asize + hsize), HEAPALIGN);
 118 
 119                 /*
 120                  * Allocate a block that is at minimum 'HEAPBLOCK' size
 121                  */
 122                 if (tsize < HEAPBLOCK)
 123                         tsize = HEAPBLOCK;
 124 
 125                 if ((nhp = dz_map(tsize)) == MAP_FAILED)
 126                         return (NULL);
 127 
 128                 nhp->lh_next = chp;
 129                 nhp->lh_free = (void *)((size_t)nhp + hsize);
 130                 nhp->lh_end = (void *)((size_t)nhp + tsize);
 131 
 132                 ld_heap = chp = nhp;
 133         }
 134         vptr = chp->lh_free;
 135 
 136         /*
 137          * Assign size to head of allocated block (used by realloc), and
 138          * memory arena as then next 8-byte aligned offset.
 139          */
 140         *((size_t *)vptr) = size;
 141         vptr = (void *)((size_t)vptr + HEAPALIGN);
 142 
 143         /*
 144          * Increment free to point to next available block
 145          */
 146         chp->lh_free = (void *)S_ROUND((size_t)chp->lh_free + asize,
 147             HEAPALIGN);
 148 
 149         return (vptr);
 150 }
 151 
 152 void *
 153 libld_realloc(void *ptr, size_t size)
 154 {
 155         size_t  psize;
 156         void    *vptr;
 157 
 158         if (ptr == NULL)
 159                 return (libld_malloc(size));
 160 
 161         /*
 162          * Size of the allocated blocks is stored *just* before the blocks
 163          * address.
 164          */
 165         psize = *((size_t *)((size_t)ptr - HEAPALIGN));
 166 
 167         /*
 168          * If the block actually fits then just return.
 169          */
 170         if (size <= psize)
 171                 return (ptr);
 172 
 173         if ((vptr = libld_malloc(size)) != NULL)
 174                 (void) memcpy(vptr, ptr, psize);
 175 
 176         return (vptr);
 177 }
 178 
 179 void
 180 /* ARGSUSED 0 */
 181 libld_free(void *ptr)
 182 {
 183 }
 184 
 185 /*
 186  * Determine if a shared object definition structure already exists and if
 187  * not create one.  These definitions provide for recording information
 188  * regarding shared objects that are still to be processed.  Once processed
 189  * shared objects are maintained on the ofl_sos list.  The information
 190  * recorded in this structure includes:
 191  *
 192  *  o   DT_USED requirements.  In these cases definitions are added during
 193  *      mapfile processing of `-' entries (see map_dash()).
 194  *
 195  *  o   implicit NEEDED entries.  As shared objects are processed from the
 196  *      command line so any of their dependencies are recorded in these
 197  *      structures for later processing (see process_dynamic()).
 198  *
 199  *  o   version requirements.  Any explicit shared objects that have version
 200  *      dependencies on other objects have their version requirements recorded.
 201  *      In these cases definitions are added during mapfile processing of `-'
 202  *      entries (see map_dash()).  Also, shared objects may have versioning
 203  *      requirements on their NEEDED entries.  These cases are added during
 204  *      their version processing (see vers_need_process()).
 205  *
 206  *      Note: Both process_dynamic() and vers_need_process() may generate the
 207  *      initial version definition structure because you can't rely on what
 208  *      section (.dynamic or .SUNW_version) may be processed first from any
 209  *      input file.
 210  */
 211 Sdf_desc *
 212 sdf_find(const char *name, APlist *alp)
 213 {
 214         Aliste          idx;
 215         Sdf_desc        *sdf;
 216 
 217         for (APLIST_TRAVERSE(alp, idx, sdf))
 218                 if (strcmp(name, sdf->sdf_name) == 0)
 219                         return (sdf);
 220 
 221         return (NULL);
 222 }
 223 
 224 Sdf_desc *
 225 sdf_add(const char *name, APlist **alpp)
 226 {
 227         Sdf_desc        *sdf;
 228 
 229         if ((sdf = libld_calloc(sizeof (Sdf_desc), 1)) == NULL)
 230                 return ((Sdf_desc *)S_ERROR);
 231 
 232         sdf->sdf_name = name;
 233 
 234         if (aplist_append(alpp, sdf, AL_CNT_OFL_LIBS) == NULL)
 235                 return ((Sdf_desc *)S_ERROR);
 236 
 237         return (sdf);
 238 }
 239 
 240 /*
 241  * Add a string, separated by a colon, to an existing string.  Typically used
 242  * to maintain filter, rpath and audit names, of which there is normally only
 243  * one string supplied anyway.
 244  */
 245 char *
 246 add_string(char *old, char *str)
 247 {
 248         char    *new;
 249 
 250         if (old) {
 251                 char    *_str;
 252                 size_t  len;
 253 
 254                 /*
 255                  * If an original string exists, make sure this new string
 256                  * doesn't get duplicated.
 257                  */
 258                 if ((_str = strstr(old, str)) != NULL) {
 259                         if (((_str == old) ||
 260                             (*(_str - 1) == *(MSG_ORIG(MSG_STR_COLON)))) &&
 261                             (_str += strlen(str)) &&
 262                             ((*_str == '\0') ||
 263                             (*_str == *(MSG_ORIG(MSG_STR_COLON)))))
 264                                 return (old);
 265                 }
 266 
 267                 len = strlen(old) + strlen(str) + 2;
 268                 if ((new = libld_calloc(1, len)) == NULL)
 269                         return ((char *)S_ERROR);
 270                 (void) snprintf(new, len, MSG_ORIG(MSG_FMT_COLPATH), old, str);
 271         } else {
 272                 if ((new = libld_malloc(strlen(str) + 1)) == NULL)
 273                         return ((char *)S_ERROR);
 274                 (void) strcpy(new, str);
 275         }
 276 
 277         return (new);
 278 }
 279 
 280 /*
 281  * The GNU ld '-wrap=XXX' and '--wrap=XXX' options correspond to our
 282  * '-z wrap=XXX'. When str2chr() does this conversion, we end up with
 283  * the return character set to 'z' and optarg set to 'XXX'. This callback
 284  * changes optarg to include the missing wrap= prefix.
 285  *
 286  * exit:
 287  *      Returns c on success, or '?' on error.
 288  */
 289 static int
 290 str2chr_wrap_cb(int c)
 291 {
 292         char    *str;
 293         size_t  len = MSG_ARG_WRAP_SIZE + strlen(optarg) + 1;
 294 
 295         if ((str = libld_malloc(len)) == NULL)
 296                 return ('?');
 297         (void) snprintf(str, len, MSG_ORIG(MSG_FMT_STRCAT),
 298             MSG_ORIG(MSG_ARG_WRAP), optarg);
 299         optarg = str;
 300         return (c);
 301 }
 302 
 303 /*
 304  * Determine whether this string, possibly with an associated option, should
 305  * be translated to an option character.  If so, update the optind and optarg
 306  * and optopt as described for short options in getopt(3c).
 307  *
 308  * entry:
 309  *      lml - Link map list for debug messages
 310  *      ndx - Starting optind for current item
 311  *      argc, argv - Command line arguments
 312  *      arg - Option to be examined
 313  *      c, opt - Option character (c) and corresponding long name (opt)
 314  *      optsz - 0 if option does not accept a value. If option does
 315  *              accept a value, strlen(opt), giving the offset to the
 316  *              value if the option and value are combined in one string.
 317  *      cbfunc - NULL, or pointer to function to call if a translation is
 318  *              successful.
 319  */
 320 static int
 321 str2chr(Lm_list *lml, int ndx, int argc, char **argv, char *arg, int c,
 322     const char *opt, size_t optsz, int cbfunc(int))
 323 {
 324         if (optsz == 0) {
 325                 /*
 326                  * Compare a single option (ie. there's no associated option
 327                  * argument).
 328                  */
 329                 if (strcmp(arg, opt) == 0) {
 330                         DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c));
 331                         optind += 1;
 332                         optopt = c;
 333                         return (c);
 334                 }
 335         } else if ((strcmp(arg, opt) == 0) ||
 336             ((arg[optsz] == '=') && strncmp(arg, opt, optsz) == 0)) {
 337                 /*
 338                  * Otherwise, compare the option name, which may be
 339                  * concatenated with the option argument.
 340                  */
 341                 DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c));
 342 
 343                 if (arg[optsz] == '\0') {
 344                         /*
 345                          * Optarg is the next argument (white space separated).
 346                          * Make sure an optarg is available, and if not return
 347                          * a failure to prevent any fall-through to the generic
 348                          * getopt() processing.
 349                          *
 350                          * Since we'll be completely failing this option we
 351                          * don't want to update optopt with the translation,
 352                          * but also need to set it to _something_.  Setting it
 353                          * to the '-' of the argument causes us to behave
 354                          * correctly.
 355                          */
 356                         if ((++optind + 1) > argc) {
 357                                 optopt = arg[0];
 358                                 return ('?');
 359                         }
 360                         optarg = argv[optind];
 361                         optind++;
 362                 } else {
 363                         /*
 364                          * GNU option/option argument pairs can be represented
 365                          * with a "=" separator.  If this is the case, remove
 366                          * the separator.
 367                          */
 368                         optarg = &arg[optsz];
 369                         optind++;
 370                         if (*optarg == '=') {
 371                                 if (*(++optarg) == '\0')
 372                                         optopt = arg[0];
 373                                         return ('?');
 374                         }
 375                 }
 376 
 377                 if (cbfunc != NULL)
 378                         c = (*cbfunc)(c);
 379                 optopt = c;
 380                 return (c);
 381         }
 382         return (0);
 383 }
 384 
 385 /*
 386  * Parse an individual option.  The intent of this function is to determine if
 387  * any known, non-Solaris options have been passed to ld(1).  This condition
 388  * can occur as a result of build configuration tools, because of users
 389  * familiarity with other systems, or simply the users preferences.  If a known
 390  * non-Solaris option can be determined, translate that option into the Solaris
 391  * counterpart.
 392  *
 393  * This function will probably never be a complete solution, as new, non-Solaris
 394  * options are discovered, their translation will have to be added.  Other
 395  * non-Solaris options are incompatible with the Solaris link-editor, and will
 396  * never be recognized.  We support what we can.
 397  */
 398 int
 399 ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
 400 {
 401         int     c;
 402 
 403         if ((optind < argc) && argv[optind] && (argv[optind][0] == '-')) {
 404                 char    *arg = &argv[optind][1];
 405 
 406                 switch (*arg) {
 407                 case 'r':
 408                         /* Translate -rpath <optarg> to -R <optarg> */
 409                         if ((c = str2chr(lml, ndx, argc, argv, arg, 'R',
 410                             MSG_ORIG(MSG_ARG_T_RPATH),
 411                             MSG_ARG_T_RPATH_SIZE, NULL)) != 0) {
 412                                 return (c);
 413                         }
 414                         break;
 415                 case 's':
 416                         /* Translate -shared to -G */
 417                         if ((c = str2chr(lml, ndx, argc, argv, arg, 'G',
 418                             MSG_ORIG(MSG_ARG_T_SHARED), 0, NULL)) != 0) {
 419                                 return (c);
 420 
 421                         /* Translate -soname <optarg> to -h <optarg> */
 422                         } else if ((c = str2chr(lml, ndx, argc, argv, arg, 'h',
 423                             MSG_ORIG(MSG_ARG_T_SONAME),
 424                             MSG_ARG_T_SONAME_SIZE, NULL)) != 0) {
 425                                 return (c);
 426                         }
 427                         break;
 428                 case 'w':
 429                         /* Translate -wrap to -z wrap= */
 430                         if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 431                             MSG_ORIG(MSG_ARG_T_WRAP) + 1,
 432                             MSG_ARG_T_WRAP_SIZE - 1, str2chr_wrap_cb)) != 0) {
 433                                 return (c);
 434                         }
 435                         break;
 436                 case '(':
 437                         /*
 438                          * Translate -( to -z rescan-start
 439                          */
 440                         if ((c = str2chr(lml, ndx, argc, argv,
 441                             arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0, NULL)) !=
 442                             0) {
 443                                 optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_START);
 444                                 return (c);
 445                         }
 446                         break;
 447                 case ')':
 448                         /*
 449                          * Translate -) to -z rescan-end
 450                          */
 451                         if ((c = str2chr(lml, ndx, argc, argv,
 452                             arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0, NULL)) !=
 453                             0) {
 454                                 optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_END);
 455                                 return (c);
 456                         }
 457                         break;
 458                 case '-':
 459                         switch (*(arg + 1)) {
 460                         case 'a':
 461                                 /*
 462                                  * Translate --allow-multiple-definition to
 463                                  * -zmuldefs
 464                                  */
 465                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 466                                     MSG_ORIG(MSG_ARG_T_MULDEFS), 0, NULL)) !=
 467                                     0) {
 468                                         optarg =
 469                                             (char *)MSG_ORIG(MSG_ARG_MULDEFS);
 470                                         return (c);
 471 
 472                                 /*
 473                                  * Translate --auxiliary <optarg> to
 474                                  * -f <optarg>
 475                                  */
 476                                 } else if ((c = str2chr(lml, argc, ndx, argv,
 477                                     arg, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR),
 478                                     MSG_ARG_T_AUXFLTR_SIZE, NULL)) != 0) {
 479                                         return (c);
 480                                 }
 481                                 break;
 482                         case 'd':
 483                                 /*
 484                                  * Translate --dynamic-linker <optarg> to
 485                                  * -I <optarg>
 486                                  */
 487                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'I',
 488                                     MSG_ORIG(MSG_ARG_T_INTERP),
 489                                     MSG_ARG_T_INTERP_SIZE, NULL)) != 0) {
 490                                         return (c);
 491                                 }
 492                                 break;
 493                         case 'e':
 494                                 /* Translate --entry <optarg> to -e <optarg> */
 495                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'e',
 496                                     MSG_ORIG(MSG_ARG_T_ENTRY),
 497                                     MSG_ARG_T_ENTRY_SIZE, NULL)) != 0) {
 498                                         return (c);
 499                                 }
 500                                 /*
 501                                  * Translate --end-group to -z rescan-end
 502                                  */
 503                                 if ((c = str2chr(lml, ndx, argc, argv,
 504                                     arg, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP),
 505                                     0, NULL)) != 0) {
 506                                         optarg = (char *)
 507                                             MSG_ORIG(MSG_ARG_RESCAN_END);
 508                                         return (c);
 509                                 }
 510                                 break;
 511                         case 'f':
 512                                 /*
 513                                  * Translate --fatal-warnings to
 514                                  * -z fatal-warnings.
 515                                  */
 516                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 517                                     MSG_ORIG(MSG_ARG_T_FATWARN),
 518                                     0, NULL)) != 0) {
 519                                         optarg = (char *)
 520                                             MSG_ORIG(MSG_ARG_FATWARN);
 521                                         return (c);
 522                                 }
 523                                 /* Translate --filter <optarg> to -F <optarg> */
 524                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'F',
 525                                     MSG_ORIG(MSG_ARG_T_STDFLTR),
 526                                     MSG_ARG_T_STDFLTR_SIZE, NULL)) != 0) {
 527                                         return (c);
 528                                 }
 529                                 break;
 530                         case 'h':
 531                                 /* Translate --help to -zhelp */
 532                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 533                                     MSG_ORIG(MSG_ARG_T_HELP), 0, NULL)) !=
 534                                     0) {
 535                                         optarg = (char *)MSG_ORIG(MSG_ARG_HELP);
 536                                         return (c);
 537                                 }
 538                                 break;
 539                         case 'l':
 540                                 /*
 541                                  * Translate --library <optarg> to -l <optarg>
 542                                  */
 543                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'l',
 544                                     MSG_ORIG(MSG_ARG_T_LIBRARY),
 545                                     MSG_ARG_T_LIBRARY_SIZE, NULL)) != 0) {
 546                                         return (c);
 547 
 548                                 /*
 549                                  * Translate --library-path <optarg> to
 550                                  * -L <optarg>
 551                                  */
 552                                 } else if ((c = str2chr(lml, ndx, argc, argv,
 553                                     arg, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH),
 554                                     MSG_ARG_T_LIBPATH_SIZE, NULL)) != 0) {
 555                                         return (c);
 556                                 }
 557                                 break;
 558                         case 'n':
 559                                 /*
 560                                  * Translate --no-fatal-warnings to
 561                                  * -z nofatal-warnings.
 562                                  */
 563                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 564                                     MSG_ORIG(MSG_ARG_T_NOFATWARN),
 565                                     0, NULL)) != 0) {
 566                                         optarg = (char *)
 567                                             MSG_ORIG(MSG_ARG_NOFATWARN);
 568                                         return (c);
 569                                 }
 570 
 571                                 /* Translate --no-undefined to -zdefs */
 572                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 573                                     MSG_ORIG(MSG_ARG_T_NOUNDEF), 0, NULL)) !=
 574                                     0) {
 575                                         optarg = (char *)MSG_ORIG(MSG_ARG_DEFS);
 576                                         return (c);
 577 
 578                                 /*
 579                                  * Translate --no-whole-archive to
 580                                  * -z defaultextract
 581                                  */
 582                                 } else if ((c = str2chr(lml, ndx, argc, argv,
 583                                     arg, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC),
 584                                     0, NULL)) != 0) {
 585                                         optarg =
 586                                             (char *)MSG_ORIG(MSG_ARG_DFLEXTRT);
 587                                         return (c);
 588                                 }
 589                                 break;
 590                         case 'o':
 591                                 /* Translate --output <optarg> to -o <optarg> */
 592                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'o',
 593                                     MSG_ORIG(MSG_ARG_T_OUTPUT),
 594                                     MSG_ARG_T_OUTPUT_SIZE, NULL)) != 0) {
 595                                         return (c);
 596                                 }
 597                                 break;
 598                         case 'r':
 599                                 /* Translate --relocatable to -r */
 600                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'r',
 601                                     MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0,
 602                                     NULL)) != 0) {
 603                                         return (c);
 604                                 }
 605                                 break;
 606                         case 's':
 607                                 /* Translate --strip-all to -s */
 608                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 's',
 609                                     MSG_ORIG(MSG_ARG_T_STRIP), 0, NULL)) !=
 610                                     0) {
 611                                         return (c);
 612                                 }
 613                                 /*
 614                                  * Translate --start-group to -z rescan-start
 615                                  */
 616                                 if ((c = str2chr(lml, ndx, argc, argv,
 617                                     arg, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP),
 618                                     0, NULL)) != 0) {
 619                                         optarg = (char *)
 620                                             MSG_ORIG(MSG_ARG_RESCAN_START);
 621                                         return (c);
 622                                 }
 623                                 break;
 624                         case 'u':
 625                                 /*
 626                                  * Translate --undefined <optarg> to
 627                                  * -u <optarg>
 628                                  */
 629                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'u',
 630                                     MSG_ORIG(MSG_ARG_T_UNDEF),
 631                                     MSG_ARG_T_UNDEF_SIZE, NULL)) != 0) {
 632                                         return (c);
 633                                 }
 634                                 break;
 635                         case 'v':
 636                                 /* Translate --version to -V */
 637                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'V',
 638                                     MSG_ORIG(MSG_ARG_T_VERSION), 0, NULL)) !=
 639                                     0) {
 640                                         return (c);
 641                                 }
 642                                 break;
 643                         case 'w':
 644                                 /*
 645                                  * Translate --whole-archive to -z alltextract
 646                                  */
 647                                 if ((c = str2chr(lml, ndx, argc, argv,
 648                                     arg, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC),
 649                                     0, NULL)) != 0) {
 650                                         optarg =
 651                                             (char *)MSG_ORIG(MSG_ARG_ALLEXTRT);
 652                                         return (c);
 653                                 }
 654                                 /*
 655                                  * Translate --wrap to -z wrap=
 656                                  */
 657                                 if ((c = str2chr(lml, ndx, argc, argv,
 658                                     arg, 'z', MSG_ORIG(MSG_ARG_T_WRAP),
 659                                     MSG_ARG_T_WRAP_SIZE, str2chr_wrap_cb)) !=
 660                                     0) {
 661                                         return (c);
 662                                 }
 663                                 break;
 664                         }
 665                         break;
 666                 }
 667         }
 668 
 669         if ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
 670                 /*
 671                  * It is possible that a "-Wl," argument has been used to
 672                  * specify an option.  This isn't advertized ld(1) syntax, but
 673                  * compiler drivers and configuration tools, have been known to
 674                  * pass this compiler option to ld(1).  Strip off the "-Wl,"
 675                  * prefix and pass the option through.
 676                  */
 677                 if ((c == 'W') && (strncmp(optarg,
 678                     MSG_ORIG(MSG_ARG_T_WL), MSG_ARG_T_WL_SIZE) == 0)) {
 679                         DBG_CALL(Dbg_args_Wldel(lml, ndx, optarg));
 680                         c = optarg[MSG_ARG_T_WL_SIZE];
 681                         optarg += MSG_ARG_T_WL_SIZE + 1;
 682                 }
 683         }
 684 
 685         return (c);
 686 }
 687 
 688 /*
 689  * A compare routine for Isd_node AVL trees.
 690  */
 691 int
 692 isdavl_compare(const void *n1, const void *n2)
 693 {
 694         uint_t          hash1, hash2;
 695         const char      *st1, *st2;
 696         int             rc;
 697 
 698         hash1 = ((Isd_node *)n1)->isd_hash;
 699         hash2 = ((Isd_node *)n2)->isd_hash;
 700 
 701         if (hash1 > hash2)
 702                 return (1);
 703         if (hash1 < hash2)
 704                 return (-1);
 705 
 706         st1 = ((Isd_node *)n1)->isd_name;
 707         st2 = ((Isd_node *)n2)->isd_name;
 708 
 709         rc = strcmp(st1, st2);
 710         if (rc > 0)
 711                 return (1);
 712         if (rc < 0)
 713                 return (-1);
 714         return (0);
 715 }
 716 
 717 /*
 718  * Messaging support - funnel everything through dgettext().
 719  */
 720 const char *
 721 _libld_msg(Msg mid)
 722 {
 723         return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
 724 }
 725 
 726 /*
 727  * Determine whether a symbol name should be demangled.
 728  */
 729 const char *
 730 demangle(const char *name)
 731 {
 732         if (demangle_flag)
 733                 return (Elf_demangle_name(name));
 734         else
 735                 return (name);
 736 }
 737 
 738 /*
 739  * Compare a series of platform or machine hardware names.
 740  */
 741 int
 742 cap_names_match(Alist *alp1, Alist *alp2)
 743 {
 744         Capstr          *capstr1;
 745         Aliste          idx1;
 746         int             match = 0;
 747         Word            nitems;
 748 
 749         if ((nitems = alist_nitems(alp1)) != alist_nitems(alp2))
 750                 return (1);
 751 
 752         for (ALIST_TRAVERSE(alp1, idx1, capstr1)) {
 753                 Capstr          *capstr2;
 754                 Aliste          idx2;
 755 
 756                 for (ALIST_TRAVERSE(alp2, idx2, capstr2)) {
 757                         if (strcmp(capstr1->cs_str, capstr2->cs_str))
 758                                 continue;
 759 
 760                         match++;
 761                         break;
 762                 }
 763         }
 764 
 765         if (nitems == match)
 766                 return (0);
 767 
 768         return (1);
 769 }