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