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