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