1/* 2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23#import <stdio.h> 24#import <stdlib.h> 25 26#import "stuff/ofile.h" 27#import "stuff/errors.h" 28#import "stuff/bytesex.h" 29#import "stuff/allocate.h" 30 31/* name of the program for error messages (argv[0]) */ 32__private_extern__ char *progname = NULL; 33 34/* The filenames of the old and new dylib */ 35static char *old_dylib = NULL; 36static char *new_dylib = NULL; 37 38/* 39 * This is a flag use by process_old() and compare() to make sure each 40 * architecture in the old library is in the new library. 41 */ 42static enum bool arch_processed = FALSE; 43static char *arch_name_being_processed = NULL; 44 45/* The result of the dylib comparison */ 46static enum bool compatible = TRUE; 47 48/* the byte sex of the machine this program is running on */ 49static enum byte_sex host_byte_sex = UNKNOWN_BYTE_SEX; 50 51/* 52 * These are pointers to strings and symbols used to search of the table of 53 * contents of a library. These have to be static and not local so that 54 * check_global_symbols() can set them and that dylib_bsearch() can use them. 55 */ 56static char *strings = NULL; 57static struct nlist *symbols = NULL; 58static struct nlist_64 *symbols64 = NULL; 59 60static void process_old( 61 struct ofile *ofile, 62 char *arch_name, 63 void *cookie); 64 65static void compare( 66 struct ofile *new_ofile, 67 char *arch_name, 68 void *cookie); 69 70static void check_dylib( 71 struct ofile *ofile, 72 char *arch_name); 73 74static void check_global_symbols( 75 struct ofile *new_ofile, 76 struct ofile *old_ofile, 77 char *arch_name, 78 enum bool new_api_allowed); 79 80static int dylib_bsearch( 81 const char *symbol_name, 82 const struct dylib_table_of_contents *toc); 83 84static int dylib_bsearch64( 85 const char *symbol_name, 86 const struct dylib_table_of_contents *toc); 87 88static int nlist_bsearch( 89 const char *symbol_name, 90 const struct nlist *sym); 91 92static int nlist_bsearch64( 93 const char *symbol_name, 94 const struct nlist_64 *sym64); 95 96/* apple_version is created by the libstuff/Makefile */ 97extern char apple_version[]; 98char *version = apple_version; 99 100/* 101 * The program cmpdylib. This compares an old and an new dynamic shared library 102 * for compatiblity. Usage: 103 * 104 * cmpdylib old_dylib new_dylib 105 * 106 * It exits non-zero for incompatible libraries and prints why the libraries are 107 * incompatible. It exit zero and prints nothing for compatible libraries. 108 */ 109int 110main( 111int argc, 112char *argv[], 113char *envp[]) 114{ 115 progname = argv[0]; 116 host_byte_sex = get_host_byte_sex(); 117 118 if(argc != 3){ 119 fprintf(stderr, "Usage: %s old_dylib new_dylib\n", progname); 120 exit(EXIT_FAILURE); 121 } 122 old_dylib = argv[1]; 123 new_dylib = argv[2]; 124 125 ofile_process(old_dylib, NULL, 0, TRUE, TRUE, TRUE, FALSE, process_old, 126 NULL); 127 128 if(compatible == TRUE) 129 return(EXIT_SUCCESS); 130 else 131 return(EXIT_FAILURE); 132} 133 134/* 135 * process_old() is called once for each architecture in the old dynamic shared 136 * library and then causes compare() to be called for the same architecture 137 * in the new dynamic shared library. 138 */ 139static 140void 141process_old( 142struct ofile *old_ofile, 143char *arch_name, 144void *cookie) 145{ 146 struct arch_flag arch_flag; 147 148 /* check to make sure this is a dynamic shared library */ 149 check_dylib(old_ofile, arch_name); 150 151 /* fill in the architecure info */ 152 arch_flag.name = (char *)get_arch_name_from_types( 153 old_ofile->mh_cputype, 154 old_ofile->mh_cpusubtype); 155 arch_flag.cputype = old_ofile->mh_cputype; 156 arch_flag.cpusubtype = old_ofile->mh_cpusubtype; 157 158 arch_processed = FALSE; 159 arch_name_being_processed = arch_name; 160 161 ofile_process(new_dylib, &arch_flag, 1, FALSE, TRUE, TRUE, FALSE, 162 compare, old_ofile); 163 164 if(arch_processed == FALSE) 165 fatal("new dynamic shared library: %s does not contain " 166 "architecture %s\n", new_dylib, arch_flag.name); 167} 168 169/* 170 * compare() checks the new dynamic shared library against the old one for the 171 * same architecture. The old dynamic shared library's ofile struct is passed 172 * as the cookie. 173 */ 174static 175void 176compare( 177struct ofile *new_ofile, 178char *arch_name, 179void *cookie) 180{ 181 uint32_t i; 182 struct load_command *lc; 183 struct ofile *old_ofile; 184 struct dylib_command *old_dl, *new_dl; 185 char *old_install_name, *new_install_name; 186 enum bool new_api_allowed; 187 uint32_t ncmds; 188 189 arch_name = arch_name_being_processed; 190 191 /* check to make sure this is a dynamic shared library */ 192 check_dylib(new_ofile, arch_name); 193 194 old_ofile = (struct ofile *)cookie; 195 196 /* Get the LC_ID_DYLIB from the old dylib */ 197 old_dl = NULL; 198 lc = old_ofile->load_commands; 199 if(old_ofile->mh != NULL) 200 ncmds = old_ofile->mh->ncmds; 201 else 202 ncmds = old_ofile->mh64->ncmds; 203 for(i = 0; i < ncmds; i++){ 204 if(old_dl == NULL && lc->cmd == LC_ID_DYLIB){ 205 old_dl = (struct dylib_command *)lc; 206 } 207 lc = (struct load_command *)((char *)lc + lc->cmdsize); 208 } 209 if(old_dl == NULL){ 210 if(arch_name != NULL) 211 fatal("malformed dynamic shared library: %s (for architecture " 212 "%s) (has no dylib id command)", old_dylib, arch_name); 213 else 214 fatal("malformed dynamic shared library: %s (has no dylib id " 215 "command)", old_dylib); 216 } 217 old_install_name = (char *)old_dl + old_dl->dylib.name.offset; 218 if(old_dl->dylib.current_version < 219 old_dl->dylib.compatibility_version){ 220 if(arch_name != NULL) 221 fatal("malformed dynamic shared library: %s (for architecture " 222 "%s) (current version less than compatibility_version)", 223 old_dylib, arch_name); 224 else 225 fatal("malformed dynamic shared library: %s (current version " 226 "less than compatibility_version)", old_dylib); 227 } 228 229 /* Get the LC_ID_DYLIB from the new dylib */ 230 new_dl = NULL; 231 lc = new_ofile->load_commands; 232 if(new_ofile->mh != NULL) 233 ncmds = new_ofile->mh->ncmds; 234 else 235 ncmds = new_ofile->mh64->ncmds; 236 for(i = 0; i < ncmds; i++){ 237 if(new_dl == NULL && lc->cmd == LC_ID_DYLIB){ 238 new_dl = (struct dylib_command *)lc; 239 } 240 lc = (struct load_command *)((char *)lc + lc->cmdsize); 241 } 242 if(new_dl == NULL){ 243 if(arch_name != NULL) 244 fatal("malformed dynamic shared library: %s (for architecture " 245 "%s) (has no dylib id command)", new_dylib, arch_name); 246 else 247 fatal("malformed dynamic shared library: %s (has no dylib id " 248 "command)", new_dylib); 249 } 250 new_install_name = (char *)new_dl + new_dl->dylib.name.offset; 251 if(new_dl->dylib.current_version < 252 new_dl->dylib.compatibility_version){ 253 if(arch_name != NULL) 254 fatal("malformed dynamic shared library: %s (for architecture " 255 "%s) (current version less than compatibility_version)", 256 new_dylib, arch_name); 257 else 258 fatal("malformed dynamic shared library: %s (current version " 259 "less than compatibility_version)", new_dylib); 260 } 261 262 /* check the values of the LC_ID_DYLIB's */ 263 if(strcmp(old_install_name, new_install_name) != 0){ 264 if(arch_name != NULL) 265 printf("For architecture %s ", arch_name); 266 printf("dynamic shared libraries have different install names (%s " 267 "and %s)\n", old_install_name, new_install_name); 268 compatible = FALSE; 269 } 270 if(old_dl->dylib.current_version > 271 new_dl->dylib.current_version){ 272 if(arch_name != NULL) 273 printf("For architecture %s ", arch_name); 274 printf("current version of old dynamic shared library (%u) " 275 "greater than new dynamic shared library (%u)\n", 276 old_dl->dylib.current_version,new_dl->dylib.current_version); 277 compatible = FALSE; 278 } 279 if(old_dl->dylib.compatibility_version > 280 new_dl->dylib.compatibility_version){ 281 if(arch_name != NULL) 282 printf("For architecture %s ", arch_name); 283 printf("compatibility version of old dynamic shared library (%u) " 284 "greater than new dynamic shared library (%u)\n", 285 old_dl->dylib.compatibility_version, 286 new_dl->dylib.compatibility_version); 287 compatible = FALSE; 288 new_api_allowed = TRUE; 289 } 290 else{ 291 if(new_dl->dylib.compatibility_version != 292 old_dl->dylib.compatibility_version) 293 new_api_allowed = TRUE; 294 else 295 new_api_allowed = FALSE; 296 } 297 298 check_global_symbols(new_ofile, old_ofile, arch_name, new_api_allowed); 299 300 arch_processed = TRUE; 301} 302 303/* 304 * check_dylib() checks to make sure this is a dynamic shared library. If not 305 * it prints an error and exits. 306 */ 307static 308void 309check_dylib( 310struct ofile *ofile, 311char *arch_name) 312{ 313 if(ofile->file_type == OFILE_FAT){ 314 if(ofile->arch_type != OFILE_Mach_O || 315 (ofile->mh_filetype != MH_DYLIB && 316 ofile->mh_filetype != MH_DYLIB_STUB)) 317 fatal("for architecture %s file: %s is not a dynamic shared " 318 "library", ofile->arch_flag.name, ofile->file_name); 319 } 320 else 321 if(ofile->file_type != OFILE_Mach_O || 322 (ofile->mh_filetype != MH_DYLIB && 323 ofile->mh_filetype != MH_DYLIB_STUB)) 324 fatal("file: %s is not a dynamic shared library", 325 ofile->file_name); 326} 327 328/* 329 * check_global_symbols() checks to see if all the global symbols defined in the 330 * old library are defined in the new library. If not it prints the ones not 331 * defined and sets compatible to FALSE. If new_api_allowed is FALSE then it 332 * checks to see if there are any global symbols that are in the new library 333 * that are not in the old library. If so it prints those and sets compatible 334 * to FALSE. 335 */ 336static 337void 338check_global_symbols( 339struct ofile *new_ofile, 340struct ofile *old_ofile, 341char *arch_name, 342enum bool new_api_allowed) 343{ 344 uint32_t i; 345 struct load_command *lc; 346 enum bool new_api, missing_symbols, found; 347 348 struct symtab_command *old_st, *new_st; 349 struct dysymtab_command *old_dyst, *new_dyst; 350 struct nlist *old_symbols, *new_symbols, *sym; 351 struct nlist_64 *old_symbols64, *new_symbols64, *sym64; 352 char *old_strings, *new_strings; 353 struct dylib_table_of_contents *old_tocs, *new_tocs, *toc; 354 char *symbol_name; 355 uint32_t ncmds, n_strx; 356 357 /* 358 * Pickup the symbolic info for the old dylib. 359 */ 360 old_st = NULL; 361 old_dyst = NULL; 362 lc = old_ofile->load_commands; 363 if(old_ofile->mh != NULL) 364 ncmds = old_ofile->mh->ncmds; 365 else 366 ncmds = old_ofile->mh64->ncmds; 367 for(i = 0; i < ncmds; i++){ 368 if(old_st == NULL && lc->cmd == LC_SYMTAB){ 369 old_st = (struct symtab_command *)lc; 370 } 371 else if(old_dyst == NULL && lc->cmd == LC_DYSYMTAB){ 372 old_dyst = (struct dysymtab_command *)lc; 373 } 374 lc = (struct load_command *)((char *)lc + lc->cmdsize); 375 } 376 if(old_st == NULL || old_st->nsyms == 0){ 377 if(arch_name != NULL) 378 fatal("old dynamic shared library: %s (for architecture %s) " 379 "has no symbol table", old_dylib, arch_name); 380 else 381 fatal("old dynamic shared library: %s has no symbol table", 382 old_dylib); 383 } 384 if(old_ofile->mh != NULL){ 385 old_symbols = (struct nlist *) 386 (old_ofile->object_addr + old_st->symoff); 387 old_symbols64 = NULL; 388 } 389 else{ 390 old_symbols64 = (struct nlist_64 *) 391 (old_ofile->object_addr + old_st->symoff); 392 old_symbols = NULL; 393 } 394 old_tocs = (struct dylib_table_of_contents *) 395 (old_ofile->object_addr + old_dyst->tocoff); 396 old_strings = (char *) 397 (old_ofile->object_addr + old_st->stroff); 398 if(old_ofile->object_byte_sex != host_byte_sex){ 399 if(old_ofile->mh != NULL) 400 swap_nlist(old_symbols, old_st->nsyms, host_byte_sex); 401 else 402 swap_nlist_64(old_symbols64, old_st->nsyms, host_byte_sex); 403 swap_dylib_table_of_contents(old_tocs, old_dyst->ntoc, 404 host_byte_sex); 405 } 406 for(i = 0; i < old_st->nsyms; i++){ 407 if(old_ofile->mh != NULL) 408 n_strx = old_symbols[i].n_un.n_strx; 409 else 410 n_strx = old_symbols64[i].n_un.n_strx; 411 if(n_strx != 0 && n_strx > old_st->strsize){ 412 if(arch_name != NULL) 413 fatal("malformed dynamic shared library: %s (for " 414 "architecture %s) (bad string table index for symbol " 415 "%u)", old_dylib, arch_name, i); 416 else 417 fatal("malformed dynamic shared library: %s (bad string " 418 "table index for symbol %u)", old_dylib, i); 419 } 420 } 421 for(i = 0; i < old_dyst->ntoc; i++){ 422 if(old_tocs[i].symbol_index > old_st->nsyms){ 423 if(arch_name != NULL) 424 fatal("malformed dynamic shared library: %s (for " 425 "architecture %s) (symbol_index field of table of " 426 "contents entry %u past the end of the symbol table)", 427 old_dylib, arch_name, i); 428 else 429 fatal("malformed dynamic shared library: %s (symbol_index " 430 "field of table of contents entry %u past the end of " 431 "the symbol table)", old_dylib, i); 432 } 433 } 434 435 /* 436 * Pickup the symbolic info for the new dylib. 437 */ 438 new_st = NULL; 439 new_dyst = NULL; 440 lc = new_ofile->load_commands; 441 if(new_ofile->mh != NULL) 442 ncmds = new_ofile->mh->ncmds; 443 else 444 ncmds = new_ofile->mh64->ncmds; 445 for(i = 0; i < ncmds; i++){ 446 if(new_st == NULL && lc->cmd == LC_SYMTAB){ 447 new_st = (struct symtab_command *)lc; 448 } 449 else if(new_dyst == NULL && lc->cmd == LC_DYSYMTAB){ 450 new_dyst = (struct dysymtab_command *)lc; 451 } 452 lc = (struct load_command *)((char *)lc + lc->cmdsize); 453 } 454 if(new_st == NULL || new_st->nsyms == 0){ 455 if(arch_name != NULL) 456 fatal("new dynamic shared library: %s (for architecture %s) " 457 "has no symbol table", new_dylib, arch_name); 458 else 459 fatal("new dynamic shared library: %s has no symbol table", 460 new_dylib); 461 } 462 if(new_ofile->mh != NULL){ 463 new_symbols = (struct nlist *) 464 (new_ofile->object_addr + new_st->symoff); 465 new_symbols64 = NULL; 466 } 467 else{ 468 new_symbols64 = (struct nlist_64 *) 469 (new_ofile->object_addr + new_st->symoff); 470 new_symbols = NULL; 471 } 472 new_strings = (char *) 473 (new_ofile->object_addr + new_st->stroff); 474 new_tocs = (struct dylib_table_of_contents *) 475 (new_ofile->object_addr + new_dyst->tocoff); 476 if(new_ofile->object_byte_sex != host_byte_sex){ 477 if(new_ofile->mh != NULL) 478 swap_nlist(new_symbols, new_st->nsyms, host_byte_sex); 479 else 480 swap_nlist_64(new_symbols64, new_st->nsyms, host_byte_sex); 481 swap_dylib_table_of_contents(new_tocs, new_dyst->ntoc, 482 host_byte_sex); 483 } 484 for(i = 0; i < new_st->nsyms; i++){ 485 if(new_ofile->mh != NULL) 486 n_strx = new_symbols[i].n_un.n_strx; 487 else 488 n_strx = new_symbols64[i].n_un.n_strx; 489 if(n_strx != 0 && n_strx > new_st->strsize){ 490 if(arch_name != NULL) 491 fatal("malformed dynamic shared library: %s (for " 492 "architecture %s) (bad string table index for symbol " 493 "%u)", new_dylib, arch_name, i); 494 else 495 fatal("malformed dynamic shared library: %s (bad string " 496 "table index for symbol %u)", new_dylib, i); 497 } 498 } 499 for(i = 0; i < new_dyst->ntoc; i++){ 500 if(new_tocs[i].symbol_index > new_st->nsyms){ 501 if(arch_name != NULL) 502 fatal("malformed dynamic shared library: %s (for " 503 "architecture %s) (symbol_index field of table of " 504 "contents entry %u past the end of the symbol table)", 505 new_dylib, arch_name, i); 506 else 507 fatal("malformed dynamic shared library: %s (symbol_index " 508 "field of table of contents entry %u past the end of " 509 "the symbol table)", new_dylib, i); 510 } 511 } 512 513 /* 514 * Now check to see if all the global symbols defined in the old library 515 * are defined in the new library. Prints the ones that are not and 516 * sets compatible to FALSE. 517 */ 518 missing_symbols = FALSE; 519 strings = new_strings; 520 if(new_dyst->ntoc != 0){ 521 symbols = new_symbols; 522 symbols64 = new_symbols64; 523 } 524 else{ 525 if(new_ofile->mh != NULL){ 526 symbols = new_symbols + new_dyst->iextdefsym; 527 symbols64 = NULL; 528 } 529 else{ 530 symbols64 = new_symbols64 + new_dyst->iextdefsym; 531 symbols = NULL; 532 } 533 } 534 for(i = 0; i < old_dyst->nextdefsym; i++){ 535 if(new_ofile->mh != NULL) 536 n_strx = old_symbols[i + old_dyst->iextdefsym].n_un.n_strx; 537 else 538 n_strx = old_symbols64[i + old_dyst->iextdefsym].n_un.n_strx; 539 symbol_name = old_strings + n_strx; 540 if(new_dyst->ntoc != 0){ 541 if(new_ofile->mh != NULL){ 542 toc = bsearch(symbol_name, new_tocs, new_dyst->ntoc, 543 sizeof(struct dylib_table_of_contents), 544 (int (*)(const void *, const void *)) 545 dylib_bsearch); 546 } 547 else{ 548 toc = bsearch(symbol_name, new_tocs, new_dyst->ntoc, 549 sizeof(struct dylib_table_of_contents), 550 (int (*)(const void *, const void *)) 551 dylib_bsearch64); 552 } 553 found = toc != NULL; 554 } 555 else{ 556 if(new_ofile->mh != NULL){ 557 sym = bsearch(symbol_name, symbols, new_dyst->nextdefsym, 558 sizeof(struct nlist), 559 (int (*)(const void *, const void *)) 560 nlist_bsearch); 561 found = sym != NULL; 562 } 563 else{ 564 sym64 = bsearch(symbol_name, symbols64,new_dyst->nextdefsym, 565 sizeof(struct nlist_64), 566 (int (*)(const void *, const void *)) 567 nlist_bsearch64); 568 found = sym64 != NULL; 569 } 570 } 571 if(found == FALSE){ 572 if(missing_symbols == FALSE){ 573 if(arch_name != NULL) 574 printf("For architecture %s symbols defined in %s " 575 "not defined in %s:\n", arch_name, old_dylib, 576 new_dylib); 577 else 578 printf("symbols defined in %s not defined in %s:\n", 579 old_dylib, new_dylib); 580 missing_symbols = TRUE; 581 compatible = FALSE; 582 } 583 printf("%s\n", symbol_name); 584 } 585 } 586 587 /* 588 * If new api is allowed then checking of global symbols is done. 589 */ 590 if(new_api_allowed == TRUE) 591 return; 592 593 /* 594 * New api is not allowed so check to make sure no symbols in the new 595 * library are not in the old library. 596 */ 597 new_api = FALSE; 598 strings = old_strings; 599 if(old_dyst->ntoc != 0){ 600 symbols = old_symbols; 601 symbols64 = old_symbols64; 602 } 603 else{ 604 if(old_ofile->mh != NULL){ 605 symbols = old_symbols + old_dyst->iextdefsym; 606 symbols64 = NULL; 607 } 608 else{ 609 symbols64 = old_symbols64 + old_dyst->iextdefsym; 610 symbols = NULL; 611 } 612 } 613 for(i = 0; i < new_dyst->nextdefsym; i++){ 614 if(new_ofile->mh != NULL) 615 n_strx = new_symbols[i + new_dyst->iextdefsym].n_un.n_strx; 616 else 617 n_strx = new_symbols64[i + new_dyst->iextdefsym].n_un.n_strx; 618 symbol_name = new_strings + n_strx; 619 if(old_dyst->ntoc != 0){ 620 if(new_ofile->mh != NULL){ 621 toc = bsearch(symbol_name, old_tocs, old_dyst->ntoc, 622 sizeof(struct dylib_table_of_contents), 623 (int (*)(const void *, const void *)) 624 dylib_bsearch); 625 } 626 else{ 627 toc = bsearch(symbol_name, old_tocs, old_dyst->ntoc, 628 sizeof(struct dylib_table_of_contents), 629 (int (*)(const void *, const void *)) 630 dylib_bsearch64); 631 } 632 found = toc != NULL; 633 } 634 else{ 635 if(new_ofile->mh != NULL){ 636 sym = bsearch(symbol_name, symbols, old_dyst->nextdefsym, 637 sizeof(struct nlist), 638 (int (*)(const void *, const void *)) 639 nlist_bsearch); 640 found = sym != NULL; 641 } 642 else{ 643 sym64 = bsearch(symbol_name, symbols64,old_dyst->nextdefsym, 644 sizeof(struct nlist_64), 645 (int (*)(const void *, const void *)) 646 nlist_bsearch64); 647 found = sym64 != NULL; 648 } 649 } 650 if(found == FALSE){ 651 if(new_api == FALSE){ 652 if(arch_name != NULL) 653 printf("For architecture %s compatibility versions are " 654 "the same but new symbols defined in %s not " 655 "defined in %s:\n",arch_name, new_dylib, old_dylib); 656 else 657 printf("compatibility versions are the same but new " 658 "symbols defined in %s not defined in %s:\n", 659 new_dylib, old_dylib); 660 new_api = TRUE; 661 compatible = FALSE; 662 } 663 printf("%s\n", symbol_name); 664 } 665 } 666} 667 668/* 669 * Function for bsearch() for finding a symbol name in a dylib table of 670 * contents. 671 */ 672static 673int 674dylib_bsearch( 675const char *symbol_name, 676const struct dylib_table_of_contents *toc) 677{ 678 return(strcmp(symbol_name, 679 strings + symbols[toc->symbol_index].n_un.n_strx)); 680} 681 682static 683int 684dylib_bsearch64( 685const char *symbol_name, 686const struct dylib_table_of_contents *toc) 687{ 688 return(strcmp(symbol_name, 689 strings + symbols64[toc->symbol_index].n_un.n_strx)); 690} 691 692/* 693 * Function for bsearch() for finding a symbol name in the sorted list of 694 * defined external symbols. 695 */ 696static 697int 698nlist_bsearch( 699const char *symbol_name, 700const struct nlist *sym) 701{ 702 return(strcmp(symbol_name, strings + sym->n_un.n_strx)); 703} 704 705static 706int 707nlist_bsearch64( 708const char *symbol_name, 709const struct nlist_64 *sym64) 710{ 711 return(strcmp(symbol_name, strings + sym64->n_un.n_strx)); 712} 713