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 be
 305  * translated to an option character.  If so, update the optind and optarg
 306  * 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                         return (c);
 333                 }
 334 
 335         } else if (strncmp(arg, opt, optsz) == 0) {
 336                 /*
 337                  * Otherwise, compare the option name, which may be
 338                  * concatenated with the option argument.
 339                  */
 340                 DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c));
 341 
 342                 if (arg[optsz] == '\0') {
 343                         /*
 344                          * Optarg is the next argument (white space separated).
 345                          * Make sure an optarg is available, and if not return
 346                          * a failure to prevent any fall-through to the generic
 347                          * getopt() processing.
 348                          */
 349                         if ((++optind + 1) > argc) {
 350                                 return ('?');
 351                         }
 352                         optarg = argv[optind];
 353                         optind++;
 354                 } else {
 355                         /*
 356                          * Optarg concatenated to option (no white space).
 357                          * GNU option/option argument pairs can be represented
 358                          * with a "=" separator.  If this is the case, remove
 359                          * the separator.
 360                          */
 361                         optarg = &arg[optsz];
 362                         optind++;
 363                         if (*optarg == '=') {
 364                                 if (*(++optarg) == '\0')
 365                                         return ('?');
 366                         }
 367                 }
 368 
 369                 if (cbfunc != NULL)
 370                         c = (*cbfunc)(c);
 371 
 372                 return (c);
 373         }
 374         return (0);
 375 }
 376 
 377 /*
 378  * Parse an individual option.  The intent of this function is to determine if
 379  * any known, non-Solaris options have been passed to ld(1).  This condition
 380  * can occur as a result of build configuration tools, because of users
 381  * familiarity with other systems, or simply the users preferences.  If a known
 382  * non-Solaris option can be determined, translate that option into the Solaris
 383  * counterpart.
 384  *
 385  * This function will probably never be a complete solution, as new, non-Solaris
 386  * options are discovered, their translation will have to be added.  Other
 387  * non-Solaris options are incompatible with the Solaris link-editor, and will
 388  * never be recognized.  We support what we can.
 389  */
 390 int
 391 ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
 392 {
 393         int     c;
 394 
 395         if ((optind < argc) && argv[optind] && (argv[optind][0] == '-')) {
 396                 char    *arg = &argv[optind][1];
 397 
 398                 switch (*arg) {
 399                 case 'r':
 400                         /* Translate -rpath <optarg> to -R <optarg> */
 401                         if ((c = str2chr(lml, ndx, argc, argv, arg, 'R',
 402                             MSG_ORIG(MSG_ARG_T_RPATH),
 403                             MSG_ARG_T_RPATH_SIZE, NULL)) != 0) {
 404                                 return (c);
 405                         }
 406                         break;
 407                 case 's':
 408                         /* Translate -shared to -G */
 409                         if ((c = str2chr(lml, ndx, argc, argv, arg, 'G',
 410                             MSG_ORIG(MSG_ARG_T_SHARED), 0, NULL)) != 0) {
 411                                 return (c);
 412 
 413                         /* Translate -soname <optarg> to -h <optarg> */
 414                         } else if ((c = str2chr(lml, ndx, argc, argv, arg, 'h',
 415                             MSG_ORIG(MSG_ARG_T_SONAME),
 416                             MSG_ARG_T_SONAME_SIZE, NULL)) != 0) {
 417                                 return (c);
 418                         }
 419                         break;
 420                 case 'w':
 421                         /* Translate -wrap to -z wrap= */
 422                         if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 423                             MSG_ORIG(MSG_ARG_T_WRAP) + 1,
 424                             MSG_ARG_T_WRAP_SIZE - 1, str2chr_wrap_cb)) != 0) {
 425                                 return (c);
 426                         }
 427                         break;
 428                 case '(':
 429                         /*
 430                          * Translate -( to -z rescan-start
 431                          */
 432                         if ((c = str2chr(lml, ndx, argc, argv,
 433                             arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0, NULL)) !=
 434                             0) {
 435                                 optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_START);
 436                                 return (c);
 437                         }
 438                         break;
 439                 case ')':
 440                         /*
 441                          * Translate -) to -z rescan-end
 442                          */
 443                         if ((c = str2chr(lml, ndx, argc, argv,
 444                             arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0, NULL)) !=
 445                             0) {
 446                                 optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_END);
 447                                 return (c);
 448                         }
 449                         break;
 450                 case '-':
 451                         switch (*(arg + 1)) {
 452                         case 'a':
 453                                 /*
 454                                  * Translate --allow-multiple-definition to
 455                                  * -zmuldefs
 456                                  */
 457                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 458                                     MSG_ORIG(MSG_ARG_T_MULDEFS), 0, NULL)) !=
 459                                     0) {
 460                                         optarg =
 461                                             (char *)MSG_ORIG(MSG_ARG_MULDEFS);
 462                                         return (c);
 463 
 464                                 /*
 465                                  * Translate --auxiliary <optarg> to
 466                                  * -f <optarg>
 467                                  */
 468                                 } else if ((c = str2chr(lml, argc, ndx, argv,
 469                                     arg, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR),
 470                                     MSG_ARG_T_AUXFLTR_SIZE, NULL)) != 0) {
 471                                         return (c);
 472                                 }
 473                                 break;
 474                         case 'd':
 475                                 /*
 476                                  * Translate --dynamic-linker <optarg> to
 477                                  * -I <optarg>
 478                                  */
 479                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'I',
 480                                     MSG_ORIG(MSG_ARG_T_INTERP),
 481                                     MSG_ARG_T_INTERP_SIZE, NULL)) != 0) {
 482                                         return (c);
 483                                 }
 484                                 break;
 485                         case 'e':
 486                                 /* Translate --entry <optarg> to -e <optarg> */
 487                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'e',
 488                                     MSG_ORIG(MSG_ARG_T_ENTRY),
 489                                     MSG_ARG_T_ENTRY_SIZE, NULL)) != 0) {
 490                                         return (c);
 491                                 }
 492                                 /*
 493                                  * Translate --end-group to -z rescan-end
 494                                  */
 495                                 if ((c = str2chr(lml, ndx, argc, argv,
 496                                     arg, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP),
 497                                     0, NULL)) != 0) {
 498                                         optarg = (char *)
 499                                             MSG_ORIG(MSG_ARG_RESCAN_END);
 500                                         return (c);
 501                                 }
 502                                 break;
 503                         case 'f':
 504                                 /*
 505                                  * Translate --fatal-warnings to
 506                                  * -z fatal-warnings.
 507                                  */
 508                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 509                                     MSG_ORIG(MSG_ARG_T_FATWARN),
 510                                     0, NULL)) != 0) {
 511                                         optarg = (char *)
 512                                             MSG_ORIG(MSG_ARG_FATWARN);
 513                                         return (c);
 514                                 }
 515                                 /* Translate --filter <optarg> to -F <optarg> */
 516                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'F',
 517                                     MSG_ORIG(MSG_ARG_T_STDFLTR),
 518                                     MSG_ARG_T_STDFLTR_SIZE, NULL)) != 0) {
 519                                         return (c);
 520                                 }
 521                                 break;
 522                         case 'h':
 523                                 /* Translate --help to -zhelp */
 524                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 525                                     MSG_ORIG(MSG_ARG_T_HELP), 0, NULL)) !=
 526                                     0) {
 527                                         optarg = (char *)MSG_ORIG(MSG_ARG_HELP);
 528                                         return (c);
 529                                 }
 530                                 break;
 531                         case 'l':
 532                                 /*
 533                                  * Translate --library <optarg> to -l <optarg>
 534                                  */
 535                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'l',
 536                                     MSG_ORIG(MSG_ARG_T_LIBRARY),
 537                                     MSG_ARG_T_LIBRARY_SIZE, NULL)) != 0) {
 538                                         return (c);
 539 
 540                                 /*
 541                                  * Translate --library-path <optarg> to
 542                                  * -L <optarg>
 543                                  */
 544                                 } else if ((c = str2chr(lml, ndx, argc, argv,
 545                                     arg, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH),
 546                                     MSG_ARG_T_LIBPATH_SIZE, NULL)) != 0) {
 547                                         return (c);
 548                                 }
 549                                 break;
 550                         case 'n':
 551                                 /*
 552                                  * Translate --no-fatal-warnings to
 553                                  * -z nofatal-warnings.
 554                                  */
 555                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 556                                     MSG_ORIG(MSG_ARG_T_NOFATWARN),
 557                                     0, NULL)) != 0) {
 558                                         optarg = (char *)
 559                                             MSG_ORIG(MSG_ARG_NOFATWARN);
 560                                         return (c);
 561                                 }
 562 
 563                                 /* Translate --no-undefined to -zdefs */
 564                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 565                                     MSG_ORIG(MSG_ARG_T_NOUNDEF), 0, NULL)) !=
 566                                     0) {
 567                                         optarg = (char *)MSG_ORIG(MSG_ARG_DEFS);
 568                                         return (c);
 569 
 570                                 /*
 571                                  * Translate --no-whole-archive to
 572                                  * -z defaultextract
 573                                  */
 574                                 } else if ((c = str2chr(lml, ndx, argc, argv,
 575                                     arg, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC),
 576                                     0, NULL)) != 0) {
 577                                         optarg =
 578                                             (char *)MSG_ORIG(MSG_ARG_DFLEXTRT);
 579                                         return (c);
 580                                 }
 581                                 break;
 582                         case 'o':
 583                                 /* Translate --output <optarg> to -o <optarg> */
 584                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'o',
 585                                     MSG_ORIG(MSG_ARG_T_OUTPUT),
 586                                     MSG_ARG_T_OUTPUT_SIZE, NULL)) != 0) {
 587                                         return (c);
 588                                 }
 589                                 break;
 590                         case 'r':
 591                                 /* Translate --relocatable to -r */
 592                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'r',
 593                                     MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0,
 594                                     NULL)) != 0) {
 595                                         return (c);
 596                                 }
 597                                 break;
 598                         case 's':
 599                                 /* Translate --strip-all to -s */
 600                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 's',
 601                                     MSG_ORIG(MSG_ARG_T_STRIP), 0, NULL)) !=
 602                                     0) {
 603                                         return (c);
 604                                 }
 605                                 /*
 606                                  * Translate --start-group to -z rescan-start
 607                                  */
 608                                 if ((c = str2chr(lml, ndx, argc, argv,
 609                                     arg, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP),
 610                                     0, NULL)) != 0) {
 611                                         optarg = (char *)
 612                                             MSG_ORIG(MSG_ARG_RESCAN_START);
 613                                         return (c);
 614                                 }
 615                                 break;
 616                         case 'u':
 617                                 /*
 618                                  * Translate --undefined <optarg> to
 619                                  * -u <optarg>
 620                                  */
 621                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'u',
 622                                     MSG_ORIG(MSG_ARG_T_UNDEF),
 623                                     MSG_ARG_T_UNDEF_SIZE, NULL)) != 0) {
 624                                         return (c);
 625                                 }
 626                                 break;
 627                         case 'v':
 628                                 /* Translate --version to -V */
 629                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'V',
 630                                     MSG_ORIG(MSG_ARG_T_VERSION), 0, NULL)) !=
 631                                     0) {
 632                                         return (c);
 633                                 }
 634                                 break;
 635                         case 'w':
 636                                 /*
 637                                  * Translate --whole-archive to -z alltextract
 638                                  */
 639                                 if ((c = str2chr(lml, ndx, argc, argv,
 640                                     arg, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC),
 641                                     0, NULL)) != 0) {
 642                                         optarg =
 643                                             (char *)MSG_ORIG(MSG_ARG_ALLEXTRT);
 644                                         return (c);
 645                                 }
 646                                 /*
 647                                  * Translate --wrap to -z wrap=
 648                                  */
 649                                 if ((c = str2chr(lml, ndx, argc, argv,
 650                                     arg, 'z', MSG_ORIG(MSG_ARG_T_WRAP),
 651                                     MSG_ARG_T_WRAP_SIZE, str2chr_wrap_cb)) !=
 652                                     0) {
 653                                         return (c);
 654                                 }
 655                                 break;
 656                         }
 657                         break;
 658                 }
 659         }
 660 
 661         if ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
 662                 /*
 663                  * It is possible that a "-Wl," argument has been used to
 664                  * specify an option.  This isn't advertized ld(1) syntax, but
 665                  * compiler drivers and configuration tools, have been known to
 666                  * pass this compiler option to ld(1).  Strip off the "-Wl,"
 667                  * prefix and pass the option through.
 668                  */
 669                 if ((c == 'W') && (strncmp(optarg,
 670                     MSG_ORIG(MSG_ARG_T_WL), MSG_ARG_T_WL_SIZE) == 0)) {
 671                         DBG_CALL(Dbg_args_Wldel(lml, ndx, optarg));
 672                         c = optarg[MSG_ARG_T_WL_SIZE];
 673                         optarg += MSG_ARG_T_WL_SIZE + 1;
 674                 }
 675         }
 676 
 677         return (c);
 678 }
 679 
 680 /*
 681  * A compare routine for Isd_node AVL trees.
 682  */
 683 int
 684 isdavl_compare(const void *n1, const void *n2)
 685 {
 686         uint_t          hash1, hash2;
 687         const char      *st1, *st2;
 688         int             rc;
 689 
 690         hash1 = ((Isd_node *)n1)->isd_hash;
 691         hash2 = ((Isd_node *)n2)->isd_hash;
 692 
 693         if (hash1 > hash2)
 694                 return (1);
 695         if (hash1 < hash2)
 696                 return (-1);
 697 
 698         st1 = ((Isd_node *)n1)->isd_name;
 699         st2 = ((Isd_node *)n2)->isd_name;
 700 
 701         rc = strcmp(st1, st2);
 702         if (rc > 0)
 703                 return (1);
 704         if (rc < 0)
 705                 return (-1);
 706         return (0);
 707 }
 708 
 709 /*
 710  * Messaging support - funnel everything through dgettext().
 711  */
 712 const char *
 713 _libld_msg(Msg mid)
 714 {
 715         return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
 716 }
 717 
 718 /*
 719  * Determine whether a symbol name should be demangled.
 720  */
 721 const char *
 722 demangle(const char *name)
 723 {
 724         if (demangle_flag)
 725                 return (Elf_demangle_name(name));
 726         else
 727                 return (name);
 728 }
 729 
 730 /*
 731  * Compare a series of platform or machine hardware names.
 732  */
 733 int
 734 cap_names_match(Alist *alp1, Alist *alp2)
 735 {
 736         Capstr          *capstr1;
 737         Aliste          idx1;
 738         int             match = 0;
 739         Word            nitems;
 740 
 741         if ((nitems = alist_nitems(alp1)) != alist_nitems(alp2))
 742                 return (1);
 743 
 744         for (ALIST_TRAVERSE(alp1, idx1, capstr1)) {
 745                 Capstr          *capstr2;
 746                 Aliste          idx2;
 747 
 748                 for (ALIST_TRAVERSE(alp2, idx2, capstr2)) {
 749                         if (strcmp(capstr1->cs_str, capstr2->cs_str))
 750                                 continue;
 751 
 752                         match++;
 753                         break;
 754                 }
 755         }
 756 
 757         if (nitems == match)
 758                 return (0);
 759 
 760         return (1);
 761 }