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 --as-needed to -zignore
 464                                  */
 465                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 466                                     MSG_ORIG(MSG_ARG_T_ASNEEDED), 0, NULL)) !=
 467                                     0) {
 468                                         optarg =
 469                                             (char *)MSG_ORIG(MSG_ARG_IGNORE);
 470                                         return (c);
 471                                 }
 472                                 /*
 473                                  * Translate --allow-multiple-definition to
 474                                  * -zmuldefs
 475                                  */
 476                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 477                                     MSG_ORIG(MSG_ARG_T_MULDEFS), 0, NULL)) !=
 478                                     0) {
 479                                         optarg =
 480                                             (char *)MSG_ORIG(MSG_ARG_MULDEFS);
 481                                         return (c);
 482                                 }
 483                                 /*
 484                                  * Translate --auxiliary <optarg> to
 485                                  * -f <optarg>
 486                                  */
 487                                 if ((c = str2chr(lml, argc, ndx, argv,
 488                                     arg, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR),
 489                                     MSG_ARG_T_AUXFLTR_SIZE, NULL)) != 0) {
 490                                         return (c);
 491                                 }
 492                                 break;
 493                         case 'd':
 494                                 /*
 495                                  * Translate --dynamic-linker <optarg> to
 496                                  * -I <optarg>
 497                                  */
 498                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'I',
 499                                     MSG_ORIG(MSG_ARG_T_INTERP),
 500                                     MSG_ARG_T_INTERP_SIZE, NULL)) != 0) {
 501                                         return (c);
 502                                 }
 503                                 break;
 504                         case 'e':
 505                                 /* Translate --entry <optarg> to -e <optarg> */
 506                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'e',
 507                                     MSG_ORIG(MSG_ARG_T_ENTRY),
 508                                     MSG_ARG_T_ENTRY_SIZE, NULL)) != 0) {
 509                                         return (c);
 510                                 }
 511                                 /*
 512                                  * Translate --end-group to -z rescan-end
 513                                  */
 514                                 if ((c = str2chr(lml, ndx, argc, argv,
 515                                     arg, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP),
 516                                     0, NULL)) != 0) {
 517                                         optarg = (char *)
 518                                             MSG_ORIG(MSG_ARG_RESCAN_END);
 519                                         return (c);
 520                                 }
 521                                 break;
 522                         case 'f':
 523                                 /*
 524                                  * Translate --fatal-warnings to
 525                                  * -z fatal-warnings.
 526                                  */
 527                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 528                                     MSG_ORIG(MSG_ARG_T_FATWARN),
 529                                     0, NULL)) != 0) {
 530                                         optarg = (char *)
 531                                             MSG_ORIG(MSG_ARG_FATWARN);
 532                                         return (c);
 533                                 }
 534                                 /* Translate --filter <optarg> to -F <optarg> */
 535                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'F',
 536                                     MSG_ORIG(MSG_ARG_T_STDFLTR),
 537                                     MSG_ARG_T_STDFLTR_SIZE, NULL)) != 0) {
 538                                         return (c);
 539                                 }
 540                                 break;
 541                         case 'h':
 542                                 /* Translate --help to -zhelp */
 543                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 544                                     MSG_ORIG(MSG_ARG_T_HELP), 0, NULL)) !=
 545                                     0) {
 546                                         optarg = (char *)MSG_ORIG(MSG_ARG_HELP);
 547                                         return (c);
 548                                 }
 549                                 break;
 550                         case 'l':
 551                                 /*
 552                                  * Translate --library <optarg> to -l <optarg>
 553                                  */
 554                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'l',
 555                                     MSG_ORIG(MSG_ARG_T_LIBRARY),
 556                                     MSG_ARG_T_LIBRARY_SIZE, NULL)) != 0) {
 557                                         return (c);
 558 
 559                                 /*
 560                                  * Translate --library-path <optarg> to
 561                                  * -L <optarg>
 562                                  */
 563                                 } else if ((c = str2chr(lml, ndx, argc, argv,
 564                                     arg, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH),
 565                                     MSG_ARG_T_LIBPATH_SIZE, NULL)) != 0) {
 566                                         return (c);
 567                                 }
 568                                 break;
 569                         case 'n':
 570                                 /*
 571                                  * Translate --no-as-needed to -zrecord
 572                                  */
 573                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 574                                     MSG_ORIG(MSG_ARG_T_NOASNEEDED), 0, NULL)) !=
 575                                     0) {
 576                                         optarg =
 577                                             (char *)MSG_ORIG(MSG_ARG_RECORD);
 578                                         return (c);
 579                                 }
 580                                 /*
 581                                  * Translate --no-fatal-warnings to
 582                                  * -z nofatal-warnings.
 583                                  */
 584                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 585                                     MSG_ORIG(MSG_ARG_T_NOFATWARN),
 586                                     0, NULL)) != 0) {
 587                                         optarg = (char *)
 588                                             MSG_ORIG(MSG_ARG_NOFATWARN);
 589                                         return (c);
 590                                 }
 591 
 592                                 /* Translate --no-undefined to -zdefs */
 593                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
 594                                     MSG_ORIG(MSG_ARG_T_NOUNDEF), 0, NULL)) !=
 595                                     0) {
 596                                         optarg = (char *)MSG_ORIG(MSG_ARG_DEFS);
 597                                         return (c);
 598 
 599                                 /*
 600                                  * Translate --no-whole-archive to
 601                                  * -z defaultextract
 602                                  */
 603                                 } else if ((c = str2chr(lml, ndx, argc, argv,
 604                                     arg, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC),
 605                                     0, NULL)) != 0) {
 606                                         optarg =
 607                                             (char *)MSG_ORIG(MSG_ARG_DFLEXTRT);
 608                                         return (c);
 609                                 }
 610                                 break;
 611                         case 'o':
 612                                 /* Translate --output <optarg> to -o <optarg> */
 613                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'o',
 614                                     MSG_ORIG(MSG_ARG_T_OUTPUT),
 615                                     MSG_ARG_T_OUTPUT_SIZE, NULL)) != 0) {
 616                                         return (c);
 617                                 }
 618                                 break;
 619                         case 'r':
 620                                 /* Translate --relocatable to -r */
 621                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'r',
 622                                     MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0,
 623                                     NULL)) != 0) {
 624                                         return (c);
 625                                 }
 626                                 break;
 627                         case 's':
 628                                 /* Translate --strip-all to -s */
 629                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 's',
 630                                     MSG_ORIG(MSG_ARG_T_STRIP), 0, NULL)) !=
 631                                     0) {
 632                                         return (c);
 633                                 }
 634                                 /*
 635                                  * Translate --start-group to -z rescan-start
 636                                  */
 637                                 if ((c = str2chr(lml, ndx, argc, argv,
 638                                     arg, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP),
 639                                     0, NULL)) != 0) {
 640                                         optarg = (char *)
 641                                             MSG_ORIG(MSG_ARG_RESCAN_START);
 642                                         return (c);
 643                                 }
 644                                 break;
 645                         case 'u':
 646                                 /*
 647                                  * Translate --undefined <optarg> to
 648                                  * -u <optarg>
 649                                  */
 650                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'u',
 651                                     MSG_ORIG(MSG_ARG_T_UNDEF),
 652                                     MSG_ARG_T_UNDEF_SIZE, NULL)) != 0) {
 653                                         return (c);
 654                                 }
 655                                 break;
 656                         case 'v':
 657                                 /* Translate --version to -V */
 658                                 if ((c = str2chr(lml, ndx, argc, argv, arg, 'V',
 659                                     MSG_ORIG(MSG_ARG_T_VERSION), 0, NULL)) !=
 660                                     0) {
 661                                         return (c);
 662                                 }
 663                                 break;
 664                         case 'w':
 665                                 /*
 666                                  * Translate --whole-archive to -z alltextract
 667                                  */
 668                                 if ((c = str2chr(lml, ndx, argc, argv,
 669                                     arg, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC),
 670                                     0, NULL)) != 0) {
 671                                         optarg =
 672                                             (char *)MSG_ORIG(MSG_ARG_ALLEXTRT);
 673                                         return (c);
 674                                 }
 675                                 /*
 676                                  * Translate --wrap to -z wrap=
 677                                  */
 678                                 if ((c = str2chr(lml, ndx, argc, argv,
 679                                     arg, 'z', MSG_ORIG(MSG_ARG_T_WRAP),
 680                                     MSG_ARG_T_WRAP_SIZE, str2chr_wrap_cb)) !=
 681                                     0) {
 682                                         return (c);
 683                                 }
 684                                 break;
 685                         }
 686                         break;
 687                 }
 688         }
 689 
 690         if ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
 691                 /*
 692                  * It is possible that a "-Wl," argument has been used to
 693                  * specify an option.  This isn't advertized ld(1) syntax, but
 694                  * compiler drivers and configuration tools, have been known to
 695                  * pass this compiler option to ld(1).  Strip off the "-Wl,"
 696                  * prefix and pass the option through.
 697                  */
 698                 if ((c == 'W') && (strncmp(optarg,
 699                     MSG_ORIG(MSG_ARG_T_WL), MSG_ARG_T_WL_SIZE) == 0)) {
 700                         DBG_CALL(Dbg_args_Wldel(lml, ndx, optarg));
 701                         c = optarg[MSG_ARG_T_WL_SIZE];
 702                         optarg += MSG_ARG_T_WL_SIZE + 1;
 703                 }
 704         }
 705 
 706         return (c);
 707 }
 708 
 709 /*
 710  * A compare routine for Isd_node AVL trees.
 711  */
 712 int
 713 isdavl_compare(const void *n1, const void *n2)
 714 {
 715         uint_t          hash1, hash2;
 716         const char      *st1, *st2;
 717         int             rc;
 718 
 719         hash1 = ((Isd_node *)n1)->isd_hash;
 720         hash2 = ((Isd_node *)n2)->isd_hash;
 721 
 722         if (hash1 > hash2)
 723                 return (1);
 724         if (hash1 < hash2)
 725                 return (-1);
 726 
 727         st1 = ((Isd_node *)n1)->isd_name;
 728         st2 = ((Isd_node *)n2)->isd_name;
 729 
 730         rc = strcmp(st1, st2);
 731         if (rc > 0)
 732                 return (1);
 733         if (rc < 0)
 734                 return (-1);
 735         return (0);
 736 }
 737 
 738 /*
 739  * Messaging support - funnel everything through dgettext().
 740  */
 741 const char *
 742 _libld_msg(Msg mid)
 743 {
 744         return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
 745 }
 746 
 747 /*
 748  * Determine whether a symbol name should be demangled.
 749  */
 750 const char *
 751 demangle(const char *name)
 752 {
 753         if (demangle_flag)
 754                 return (Elf_demangle_name(name));
 755         else
 756                 return (name);
 757 }
 758 
 759 /*
 760  * Compare a series of platform or machine hardware names.
 761  */
 762 int
 763 cap_names_match(Alist *alp1, Alist *alp2)
 764 {
 765         Capstr          *capstr1;
 766         Aliste          idx1;
 767         int             match = 0;
 768         Word            nitems;
 769 
 770         if ((nitems = alist_nitems(alp1)) != alist_nitems(alp2))
 771                 return (1);
 772 
 773         for (ALIST_TRAVERSE(alp1, idx1, capstr1)) {
 774                 Capstr          *capstr2;
 775                 Aliste          idx2;
 776 
 777                 for (ALIST_TRAVERSE(alp2, idx2, capstr2)) {
 778                         if (strcmp(capstr1->cs_str, capstr2->cs_str))
 779                                 continue;
 780 
 781                         match++;
 782                         break;
 783                 }
 784         }
 785 
 786         if (nitems == match)
 787                 return (0);
 788 
 789         return (1);
 790 }