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