1/* 2 * Copyright (c) 2006 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#include <libc.h> 24#include <errno.h> 25#include <ctype.h> 26 27#include <mach/mach_init.h> 28 29#include <sys/stat.h> 30#include <sys/file.h> 31#include <sys/mman.h> 32 33#include <mach-o/arch.h> 34#include <mach-o/fat.h> 35#include <mach-o/loader.h> 36#include <mach-o/nlist.h> 37#include <mach-o/swap.h> 38 39#include <uuid/uuid.h> 40#include <stdbool.h> 41 42#pragma mark Typedefs, Enums, Constants 43/********************************************************************* 44* Typedefs, Enums, Constants 45*********************************************************************/ 46typedef enum { 47 kErrorNone = 0, 48 kError, 49 kErrorFileAccess, 50 kErrorDiskFull, 51 kErrorDuplicate 52} ToolError; 53 54#pragma mark Function Protos 55/********************************************************************* 56* Function Protos 57*********************************************************************/ 58__private_extern__ ToolError 59readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize); 60 61__private_extern__ ToolError 62writeFile(int fd, const void * data, size_t length); 63 64__private_extern__ ToolError 65seekFile(int fd, off_t offset); 66 67extern char* __cxa_demangle (const char* mangled_name, 68 char* buf, 69 size_t* n, 70 int* status); 71 72#pragma mark Functions 73/********************************************************************* 74*********************************************************************/ 75__private_extern__ ToolError 76writeFile(int fd, const void * data, size_t length) 77{ 78 ToolError err; 79 80 if (length != (size_t)write(fd, data, length)) 81 err = kErrorDiskFull; 82 else 83 err = kErrorNone; 84 85 if (kErrorNone != err) 86 perror("couldn't write output"); 87 88 return( err ); 89} 90 91 /********************************************************************* 92 *********************************************************************/ 93__private_extern__ ToolError 94seekFile(int fd, off_t offset) 95{ 96 ToolError err; 97 98 if (offset != lseek(fd, offset, SEEK_SET)) 99 err = kErrorDiskFull; 100 else 101 err = kErrorNone; 102 103 if (kErrorNone != err) 104 perror("couldn't write output"); 105 106 return( err ); 107} 108 109/********************************************************************* 110*********************************************************************/ 111__private_extern__ ToolError 112readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize) 113{ 114 ToolError err = kErrorFileAccess; 115 int fd; 116 struct stat stat_buf; 117 118 *objAddr = 0; 119 *objSize = 0; 120 121 do 122 { 123 if((fd = open(path, O_RDONLY)) == -1) 124 continue; 125 126 if(fstat(fd, &stat_buf) == -1) 127 continue; 128 129 if (0 == (stat_buf.st_mode & S_IFREG)) 130 continue; 131 132 /* Don't try to map an empty file, it fails now due to conformance 133 * stuff (PR 4611502). 134 */ 135 if (0 == stat_buf.st_size) { 136 err = kErrorNone; 137 continue; 138 } 139 140 *objSize = stat_buf.st_size; 141 142 *objAddr = (vm_offset_t)mmap(NULL /* address */, *objSize, 143 PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE /* flags */, 144 fd, 0 /* offset */); 145 146 if ((void *)*objAddr == MAP_FAILED) { 147 *objAddr = 0; 148 *objSize = 0; 149 continue; 150 } 151 152 err = kErrorNone; 153 154 } while( false ); 155 156 if (-1 != fd) 157 { 158 close(fd); 159 } 160 if (kErrorNone != err) 161 { 162 fprintf(stderr, "couldn't read %s: %s\n", path, strerror(errno)); 163 } 164 165 return( err ); 166} 167 168 169enum { kExported = 0x00000001, kObsolete = 0x00000002 }; 170 171struct symbol { 172 char * name; 173 unsigned int name_len; 174 char * indirect; 175 unsigned int indirect_len; 176 unsigned int flags; 177 struct symbol * list; 178 unsigned int list_count; 179}; 180 181static bool issymchar( char c ) 182{ 183 return ((c > ' ') && (c <= '~') && (c != ':') && (c != '#')); 184} 185 186static bool iswhitespace( char c ) 187{ 188 return ((c == ' ') || (c == '\t')); 189} 190 191/* 192 * Function for qsort for comparing symbol list names. 193 */ 194static int 195qsort_cmp(const void * _left, const void * _right) 196{ 197 struct symbol * left = (struct symbol *) _left; 198 struct symbol * right = (struct symbol *) _right; 199 200 return (strcmp(left->name, right->name)); 201} 202 203/* 204 * Function for bsearch for finding a symbol name. 205 */ 206 207static int 208bsearch_cmp( const void * _key, const void * _cmp) 209{ 210 char * key = (char *)_key; 211 struct symbol * cmp = (struct symbol *) _cmp; 212 213 return(strcmp(key, cmp->name)); 214} 215 216struct bsearch_key 217{ 218 char * name; 219 unsigned int name_len; 220}; 221 222static int 223bsearch_cmp_prefix( const void * _key, const void * _cmp) 224{ 225 struct bsearch_key * key = (struct bsearch_key *)_key; 226 struct symbol * cmp = (struct symbol *) _cmp; 227 228 return(strncmp(key->name, cmp->name, key->name_len)); 229} 230 231static uint32_t 232count_symbols(char * file, vm_size_t file_size) 233{ 234 uint32_t nsyms = 0; 235 char * scan; 236 char * eol; 237 char * next; 238 239 for (scan = file; true; scan = next) { 240 241 eol = memchr(scan, '\n', file_size - (scan - file)); 242 if (eol == NULL) { 243 break; 244 } 245 next = eol + 1; 246 247 /* Skip empty lines. 248 */ 249 if (eol == scan) { 250 continue; 251 } 252 253 /* Skip comment lines. 254 */ 255 if (scan[0] == '#') { 256 continue; 257 } 258 259 /* Scan past any non-symbol characters at the beginning of the line. */ 260 while ((scan < eol) && !issymchar(*scan)) { 261 scan++; 262 } 263 264 /* No symbol on line? Move along. 265 */ 266 if (scan == eol) { 267 continue; 268 } 269 270 /* Skip symbols starting with '.'. 271 */ 272 if (scan[0] == '.') { 273 continue; 274 } 275 nsyms++; 276 } 277 278 return nsyms; 279} 280 281static uint32_t 282store_symbols(char * file, vm_size_t file_size, struct symbol * symbols, uint32_t idx, uint32_t max_symbols) 283{ 284 char * scan; 285 char * line; 286 char * eol; 287 char * next; 288 289 uint32_t strtabsize; 290 291 strtabsize = 0; 292 293 for (scan = file, line = file; true; scan = next, line = next) { 294 295 char * name = NULL; 296 char * name_term = NULL; 297 unsigned int name_len = 0; 298 char * indirect = NULL; 299 char * indirect_term = NULL; 300 unsigned int indirect_len = 0; 301 char * option = NULL; 302 char * option_term = NULL; 303 unsigned int option_len = 0; 304 char optionstr[256]; 305 boolean_t obsolete = 0; 306 307 eol = memchr(scan, '\n', file_size - (scan - file)); 308 if (eol == NULL) { 309 break; 310 } 311 next = eol + 1; 312 313 /* Skip empty lines. 314 */ 315 if (eol == scan) { 316 continue; 317 } 318 319 *eol = '\0'; 320 321 /* Skip comment lines. 322 */ 323 if (scan[0] == '#') { 324 continue; 325 } 326 327 /* Scan past any non-symbol characters at the beginning of the line. */ 328 while ((scan < eol) && !issymchar(*scan)) { 329 scan++; 330 } 331 332 /* No symbol on line? Move along. 333 */ 334 if (scan == eol) { 335 continue; 336 } 337 338 /* Skip symbols starting with '.'. 339 */ 340 if (scan[0] == '.') { 341 continue; 342 } 343 344 name = scan; 345 346 /* Find the end of the symbol. 347 */ 348 while ((*scan != '\0') && issymchar(*scan)) { 349 scan++; 350 } 351 352 /* Note char past end of symbol. 353 */ 354 name_term = scan; 355 356 /* Stored length must include the terminating nul char. 357 */ 358 name_len = name_term - name + 1; 359 360 /* Now look for an indirect. 361 */ 362 if (*scan != '\0') { 363 while ((*scan != '\0') && iswhitespace(*scan)) { 364 scan++; 365 } 366 if (*scan == ':') { 367 scan++; 368 while ((*scan != '\0') && iswhitespace(*scan)) { 369 scan++; 370 } 371 if (issymchar(*scan)) { 372 indirect = scan; 373 374 /* Find the end of the symbol. 375 */ 376 while ((*scan != '\0') && issymchar(*scan)) { 377 scan++; 378 } 379 380 /* Note char past end of symbol. 381 */ 382 indirect_term = scan; 383 384 /* Stored length must include the terminating nul char. 385 */ 386 indirect_len = indirect_term - indirect + 1; 387 388 } else if (*scan == '\0') { 389 fprintf(stderr, "bad format in symbol line: %s\n", line); 390 exit(1); 391 } 392 } else if (*scan != '\0' && *scan != '-') { 393 fprintf(stderr, "bad format in symbol line: %s\n", line); 394 exit(1); 395 } 396 } 397 398 /* Look for options. 399 */ 400 if (*scan != '\0') { 401 while ((*scan != '\0') && iswhitespace(*scan)) { 402 scan++; 403 } 404 405 if (*scan == '-') { 406 scan++; 407 408 if (isalpha(*scan)) { 409 option = scan; 410 411 /* Find the end of the option. 412 */ 413 while ((*scan != '\0') && isalpha(*scan)) { 414 scan++; 415 } 416 417 /* Note char past end of option. 418 */ 419 option_term = scan; 420 option_len = option_term - option; 421 422 if (option_len >= sizeof(optionstr)) { 423 fprintf(stderr, "option too long in symbol line: %s\n", line); 424 exit(1); 425 } 426 memcpy(optionstr, option, option_len); 427 optionstr[option_len] = '\0'; 428 429 /* Find the option. 430 */ 431 if (!strncmp(optionstr, "obsolete", option_len)) { 432 obsolete = TRUE; 433 } 434 435 } else if (*scan == '\0') { 436 fprintf(stderr, "bad format in symbol line: %s\n", line); 437 exit(1); 438 } 439 440 } 441 442 } 443 444 if(idx >= max_symbols) { 445 fprintf(stderr, "symbol[%d/%d] overflow: %s\n", idx, max_symbols, line); 446 exit(1); 447 } 448 449 *name_term = '\0'; 450 if (indirect_term) { 451 *indirect_term = '\0'; 452 } 453 454 symbols[idx].name = name; 455 symbols[idx].name_len = name_len; 456 symbols[idx].indirect = indirect; 457 symbols[idx].indirect_len = indirect_len; 458 symbols[idx].flags = (obsolete) ? kObsolete : 0; 459 460 strtabsize += symbols[idx].name_len + symbols[idx].indirect_len; 461 idx++; 462 } 463 464 return strtabsize; 465} 466 467/********************************************************************* 468*********************************************************************/ 469int main(int argc, char * argv[]) 470{ 471 ToolError err; 472 int i, fd; 473 const char * output_name = NULL; 474 uint32_t zero = 0, num_files = 0; 475 uint32_t filenum; 476 uint32_t strx, strtabsize, strtabpad; 477 struct symbol * import_symbols; 478 struct symbol * export_symbols; 479 uint32_t num_import_syms, num_export_syms; 480 uint32_t result_count, num_removed_syms; 481 uint32_t import_idx, export_idx; 482 const NXArchInfo * host_arch; 483 const NXArchInfo * target_arch; 484 boolean_t require_imports = true; 485 boolean_t diff = false; 486 487 488 struct file { 489 vm_offset_t mapped; 490 vm_size_t mapped_size; 491 uint32_t nsyms; 492 boolean_t import; 493 const char * path; 494 }; 495 struct file files[64]; 496 497 host_arch = NXGetLocalArchInfo(); 498 target_arch = host_arch; 499 500 for( i = 1; i < argc; i += 2) 501 { 502 boolean_t import; 503 504 if (!strcmp("-sect", argv[i])) 505 { 506 require_imports = false; 507 i--; 508 continue; 509 } 510 if (!strcmp("-diff", argv[i])) 511 { 512 require_imports = false; 513 diff = true; 514 i--; 515 continue; 516 } 517 518 if (i == (argc - 1)) 519 { 520 fprintf(stderr, "bad arguments: %s\n", argv[i]); 521 exit(1); 522 } 523 524 if (!strcmp("-arch", argv[i])) 525 { 526 target_arch = NXGetArchInfoFromName(argv[i + 1]); 527 if (!target_arch) 528 { 529 fprintf(stderr, "unknown architecture name: %s\n", argv[i+1]); 530 exit(1); 531 } 532 continue; 533 } 534 if (!strcmp("-output", argv[i])) 535 { 536 output_name = argv[i+1]; 537 continue; 538 } 539 540 if (!strcmp("-import", argv[i])) 541 import = true; 542 else if (!strcmp("-export", argv[i])) 543 import = false; 544 else 545 { 546 fprintf(stderr, "unknown option: %s\n", argv[i]); 547 exit(1); 548 } 549 550 err = readFile(argv[i+1], &files[num_files].mapped, &files[num_files].mapped_size); 551 if (kErrorNone != err) 552 exit(1); 553 554 if (files[num_files].mapped && files[num_files].mapped_size) 555 { 556 files[num_files].import = import; 557 files[num_files].path = argv[i+1]; 558 num_files++; 559 } 560 } 561 562 if (!output_name) 563 { 564 fprintf(stderr, "no output file\n"); 565 exit(1); 566 } 567 568 num_import_syms = 0; 569 num_export_syms = 0; 570 for (filenum = 0; filenum < num_files; filenum++) 571 { 572 files[filenum].nsyms = count_symbols((char *) files[filenum].mapped, files[filenum].mapped_size); 573 if (files[filenum].import) 574 num_import_syms += files[filenum].nsyms; 575 else 576 num_export_syms += files[filenum].nsyms; 577 } 578 if (!num_export_syms) 579 { 580 fprintf(stderr, "no export names\n"); 581 exit(1); 582 } 583 584 import_symbols = calloc(num_import_syms, sizeof(struct symbol)); 585 export_symbols = calloc(num_export_syms, sizeof(struct symbol)); 586 587 import_idx = 0; 588 export_idx = 0; 589 590 for (filenum = 0; filenum < num_files; filenum++) 591 { 592 if (files[filenum].import) 593 { 594 store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size, 595 import_symbols, import_idx, num_import_syms); 596 import_idx += files[filenum].nsyms; 597 } 598 else 599 { 600 store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size, 601 export_symbols, export_idx, num_export_syms); 602 export_idx += files[filenum].nsyms; 603 } 604 if (false && !files[filenum].nsyms) 605 { 606 fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path); 607 } 608 } 609 610 611 qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp); 612 qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp); 613 614 result_count = 0; 615 num_removed_syms = 0; 616 strtabsize = 4; 617 if (num_import_syms) 618 { 619 for (export_idx = 0; export_idx < num_export_syms; export_idx++) 620 { 621 struct symbol * result; 622 char * name; 623 size_t len; 624 boolean_t wild; 625 626 name = export_symbols[export_idx].indirect; 627 len = export_symbols[export_idx].indirect_len; 628 if (!name) 629 { 630 name = export_symbols[export_idx].name; 631 len = export_symbols[export_idx].name_len; 632 } 633 wild = ((len > 2) && ('*' == name[len-=2])); 634 if (wild) 635 { 636 struct bsearch_key key; 637 key.name = name; 638 key.name_len = len; 639 result = bsearch(&key, import_symbols, 640 num_import_syms, sizeof(struct symbol), &bsearch_cmp_prefix); 641 642 if (result) 643 { 644 struct symbol * first; 645 struct symbol * last; 646 647 strtabsize += (result->name_len + result->indirect_len); 648 649 first = result; 650 while (--first >= &import_symbols[0]) 651 { 652 if (bsearch_cmp_prefix(&key, first)) 653 break; 654 strtabsize += (first->name_len + first->indirect_len); 655 } 656 first++; 657 658 last = result; 659 while (++last < (&import_symbols[0] + num_import_syms)) 660 { 661 if (bsearch_cmp_prefix(&key, last)) 662 break; 663 strtabsize += (last->name_len + last->indirect_len); 664 } 665 result_count += last - first; 666 result = first; 667 export_symbols[export_idx].list = first; 668 export_symbols[export_idx].list_count = last - first; 669 export_symbols[export_idx].flags |= kExported; 670 } 671 } 672 else 673 result = bsearch(name, import_symbols, 674 num_import_syms, sizeof(struct symbol), &bsearch_cmp); 675 676 if (!result && require_imports) 677 { 678 int status; 679 char * demangled_result = 680 __cxa_demangle(export_symbols[export_idx].name + 1, NULL, NULL, &status); 681 fprintf(stderr, "exported name not in import list: %s\n", 682 demangled_result ? demangled_result : export_symbols[export_idx].name); 683// fprintf(stderr, " : %s\n", export_symbols[export_idx].name); 684 if (demangled_result) { 685 free(demangled_result); 686 } 687 num_removed_syms++; 688 } 689 if (diff) 690 { 691 if (!result) 692 result = &export_symbols[export_idx]; 693 else 694 result = NULL; 695 } 696 if (result && !wild) 697 { 698 export_symbols[export_idx].flags |= kExported; 699 strtabsize += (export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len); 700 result_count++; 701 export_symbols[export_idx].list = &export_symbols[export_idx]; 702 export_symbols[export_idx].list_count = 1; 703 } 704 } 705 } 706 strtabpad = (strtabsize + 3) & ~3; 707 708 if (require_imports && num_removed_syms) 709 { 710 err = kError; 711 goto finish; 712 } 713 714 fd = open(output_name, O_WRONLY|O_CREAT|O_TRUNC, 0755); 715 if (-1 == fd) 716 { 717 perror("couldn't write output"); 718 err = kErrorFileAccess; 719 goto finish; 720 } 721 722 struct symtab_command symcmd; 723 struct uuid_command uuidcmd; 724 off_t symsoffset; 725 726 symcmd.cmd = LC_SYMTAB; 727 symcmd.cmdsize = sizeof(symcmd); 728 symcmd.nsyms = result_count; 729 symcmd.strsize = strtabpad; 730 731 uuidcmd.cmd = LC_UUID; 732 uuidcmd.cmdsize = sizeof(uuidcmd); 733 uuid_generate(uuidcmd.uuid); 734 735 if (CPU_ARCH_ABI64 & target_arch->cputype) 736 { 737 struct mach_header_64 hdr; 738 struct segment_command_64 segcmd; 739 740 hdr.magic = MH_MAGIC_64; 741 hdr.cputype = target_arch->cputype; 742 hdr.cpusubtype = target_arch->cpusubtype; 743 hdr.filetype = MH_KEXT_BUNDLE; 744 hdr.ncmds = 3; 745 hdr.sizeofcmds = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd); 746 hdr.flags = MH_INCRLINK; 747 symsoffset = mach_vm_round_page(hdr.sizeofcmds); 748 749 segcmd.cmd = LC_SEGMENT_64; 750 segcmd.cmdsize = sizeof(segcmd); 751 strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname)); 752 segcmd.vmaddr = 0; 753 segcmd.vmsize = result_count * sizeof(struct nlist_64) + strtabpad; 754 segcmd.fileoff = symsoffset; 755 segcmd.filesize = segcmd.vmsize; 756 segcmd.maxprot = PROT_READ; 757 segcmd.initprot = PROT_READ; 758 segcmd.nsects = 0; 759 segcmd.flags = SG_NORELOC; 760 761 symcmd.symoff = symsoffset; 762 symcmd.stroff = result_count * sizeof(struct nlist_64) 763 + symcmd.symoff; 764 765 if (target_arch->byteorder != host_arch->byteorder) 766 { 767 swap_mach_header_64(&hdr, target_arch->byteorder); 768 swap_segment_command_64(&segcmd, target_arch->byteorder); 769 } 770 err = writeFile(fd, &hdr, sizeof(hdr)); 771 if (kErrorNone != err) 772 goto finish; 773 err = writeFile(fd, &segcmd, sizeof(segcmd)); 774 } 775 else 776 { 777 struct mach_header hdr; 778 struct segment_command segcmd; 779 780 hdr.magic = MH_MAGIC; 781 hdr.cputype = target_arch->cputype; 782 hdr.cpusubtype = target_arch->cpusubtype; 783 hdr.filetype = (target_arch->cputype == CPU_TYPE_I386) ? MH_OBJECT : MH_KEXT_BUNDLE; 784 hdr.ncmds = 3; 785 hdr.sizeofcmds = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd); 786 hdr.flags = MH_INCRLINK; 787 symsoffset = mach_vm_round_page(hdr.sizeofcmds); 788 789 segcmd.cmd = LC_SEGMENT; 790 segcmd.cmdsize = sizeof(segcmd); 791 strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname)); 792 segcmd.vmaddr = 0; 793 segcmd.vmsize = result_count * sizeof(struct nlist) + strtabpad; 794 segcmd.fileoff = symsoffset; 795 segcmd.filesize = segcmd.vmsize; 796 segcmd.maxprot = PROT_READ; 797 segcmd.initprot = PROT_READ; 798 segcmd.nsects = 0; 799 segcmd.flags = SG_NORELOC; 800 801 symcmd.symoff = symsoffset; 802 symcmd.stroff = result_count * sizeof(struct nlist) 803 + symcmd.symoff; 804 805 if (target_arch->byteorder != host_arch->byteorder) 806 { 807 swap_mach_header(&hdr, target_arch->byteorder); 808 swap_segment_command(&segcmd, target_arch->byteorder); 809 } 810 err = writeFile(fd, &hdr, sizeof(hdr)); 811 if (kErrorNone != err) 812 goto finish; 813 err = writeFile(fd, &segcmd, sizeof(segcmd)); 814 } 815 816 if (kErrorNone != err) 817 goto finish; 818 819 if (target_arch->byteorder != host_arch->byteorder) { 820 swap_symtab_command(&symcmd, target_arch->byteorder); 821 swap_uuid_command(&uuidcmd, target_arch->byteorder); 822 } 823 err = writeFile(fd, &symcmd, sizeof(symcmd)); 824 if (kErrorNone != err) 825 goto finish; 826 err = writeFile(fd, &uuidcmd, sizeof(uuidcmd)); 827 if (kErrorNone != err) 828 goto finish; 829 830 err = seekFile(fd, symsoffset); 831 if (kErrorNone != err) 832 goto finish; 833 834 strx = 4; 835 for (export_idx = 0; export_idx < num_export_syms; export_idx++) 836 { 837 if (!export_symbols[export_idx].name) 838 continue; 839 if (!(kExported & export_symbols[export_idx].flags)) 840 continue; 841 842 if (export_idx 843 && export_symbols[export_idx - 1].name 844 && !strcmp(export_symbols[export_idx - 1].name, export_symbols[export_idx].name)) 845 { 846 fprintf(stderr, "duplicate export: %s\n", export_symbols[export_idx - 1].name); 847 err = kErrorDuplicate; 848 goto finish; 849 } 850 851 for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) 852 { 853 854 if (export_symbols[export_idx].list != &export_symbols[export_idx]) 855 { 856 printf("wild: %s, %s\n", export_symbols[export_idx].name, 857 export_symbols[export_idx].list[import_idx].name); 858 } 859 if (CPU_ARCH_ABI64 & target_arch->cputype) 860 { 861 struct nlist_64 nl; 862 863 nl.n_sect = 0; 864 nl.n_desc = 0; 865 nl.n_un.n_strx = strx; 866 strx += export_symbols[export_idx].list[import_idx].name_len; 867 868 if (export_symbols[export_idx].flags & kObsolete) { 869 nl.n_desc |= N_DESC_DISCARDED; 870 } 871 872 if (export_symbols[export_idx].list[import_idx].indirect) 873 { 874 nl.n_type = N_INDR | N_EXT; 875 nl.n_value = strx; 876 strx += export_symbols[export_idx].list[import_idx].indirect_len; 877 } 878 else 879 { 880 nl.n_type = N_UNDF | N_EXT; 881 nl.n_value = 0; 882 } 883 884 if (target_arch->byteorder != host_arch->byteorder) 885 swap_nlist_64(&nl, 1, target_arch->byteorder); 886 887 err = writeFile(fd, &nl, sizeof(nl)); 888 } 889 else 890 { 891 struct nlist nl; 892 893 nl.n_sect = 0; 894 nl.n_desc = 0; 895 nl.n_un.n_strx = strx; 896 strx += export_symbols[export_idx].list[import_idx].name_len; 897 898 if (export_symbols[export_idx].flags & kObsolete) { 899 nl.n_desc |= N_DESC_DISCARDED; 900 } 901 902 if (export_symbols[export_idx].list[import_idx].indirect) 903 { 904 nl.n_type = N_INDR | N_EXT; 905 nl.n_value = strx; 906 strx += export_symbols[export_idx].list[import_idx].indirect_len; 907 } 908 else 909 { 910 nl.n_type = N_UNDF | N_EXT; 911 nl.n_value = 0; 912 } 913 914 if (target_arch->byteorder != host_arch->byteorder) 915 swap_nlist(&nl, 1, target_arch->byteorder); 916 917 err = writeFile(fd, &nl, sizeof(nl)); 918 } 919 } 920 921 if (kErrorNone != err) 922 goto finish; 923 } 924 925 strx = sizeof(uint32_t); 926 err = writeFile(fd, &zero, strx); 927 if (kErrorNone != err) 928 goto finish; 929 930 for (export_idx = 0; export_idx < num_export_syms; export_idx++) 931 { 932 if (!export_symbols[export_idx].name) 933 continue; 934 935 for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) 936 { 937 err = writeFile(fd, export_symbols[export_idx].list[import_idx].name, 938 export_symbols[export_idx].list[import_idx].name_len); 939 if (kErrorNone != err) 940 goto finish; 941 if (export_symbols[export_idx].list[import_idx].indirect) 942 { 943 err = writeFile(fd, export_symbols[export_idx].list[import_idx].indirect, 944 export_symbols[export_idx].list[import_idx].indirect_len); 945 if (kErrorNone != err) 946 goto finish; 947 } 948 } 949 } 950 951 err = writeFile(fd, &zero, strtabpad - strtabsize); 952 if (kErrorNone != err) 953 goto finish; 954 955 close(fd); 956 957 958finish: 959 for (filenum = 0; filenum < num_files; filenum++) { 960 // unmap file 961 if (files[filenum].mapped_size) 962 { 963 munmap((caddr_t)files[filenum].mapped, files[filenum].mapped_size); 964 files[filenum].mapped = 0; 965 files[filenum].mapped_size = 0; 966 } 967 968 } 969 970 if (kErrorNone != err) 971 { 972 if (output_name) 973 unlink(output_name); 974 exit(1); 975 } 976 else 977 exit(0); 978 return(0); 979} 980 981