]> git.saurik.com Git - apple/xnu.git/blobdiff - SETUP/kextsymboltool/kextsymboltool.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / SETUP / kextsymboltool / kextsymboltool.c
index ee46713e45049828d6542da275561feefe03717a..46f644b552d3f85206b1a9cb31ca19957ffc21b5 100644 (file)
@@ -2,14 +2,14 @@
  * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 #include <libc.h>
 #include <errno.h>
 #include <ctype.h>
 
+#include <mach/mach_init.h>
+
 #include <sys/stat.h>
 #include <sys/file.h>
 #include <sys/mman.h>
 #include <mach-o/swap.h>
 
 #include <uuid/uuid.h>
-
-#include <IOKit/IOTypes.h>
+#include <stdbool.h>
 
 #pragma mark Typedefs, Enums, Constants
 /*********************************************************************
 * Typedefs, Enums, Constants
 *********************************************************************/
 typedef enum {
-    kErrorNone = 0,
-    kError,
-    kErrorFileAccess,
-    kErrorDiskFull,
-    kErrorDuplicate
+       kErrorNone = 0,
+       kError,
+       kErrorFileAccess,
+       kErrorDiskFull,
+       kErrorDuplicate
 } ToolError;
 
 #pragma mark Function Protos
@@ -60,10 +61,13 @@ readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize);
 __private_extern__ ToolError
 writeFile(int fd, const void * data, size_t length);
 
-extern char* __cxa_demangle (const char* mangled_name,
-                                  char* buf,
-                                  size_t* n,
-                                  int* status);
+__private_extern__ ToolError
+seekFile(int fd, off_t offset);
+
+extern char* __cxa_demangle(const char* mangled_name,
+    char* buf,
+    size_t* n,
+    int* status);
 
 #pragma mark Functions
 /*********************************************************************
@@ -71,99 +75,122 @@ extern char* __cxa_demangle (const char* mangled_name,
 __private_extern__ ToolError
 writeFile(int fd, const void * data, size_t length)
 {
-    ToolError err;
+       ToolError err;
 
-    if (length != (size_t)write(fd, data, length))
-        err = kErrorDiskFull;
-    else
-        err = kErrorNone;
+       if (length != (size_t)write(fd, data, length)) {
+               err = kErrorDiskFull;
+       } else {
+               err = kErrorNone;
+       }
 
-    if (kErrorNone != err)
-        perror("couldn't write output");
+       if (kErrorNone != err) {
+               perror("couldn't write output");
+       }
 
-    return( err );
+       return err;
 }
 
 /*********************************************************************
 *********************************************************************/
 __private_extern__ ToolError
-readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize)
+seekFile(int fd, off_t offset)
 {
-    ToolError err = kErrorFileAccess;
-    int fd;
-    struct stat stat_buf;
-
-    *objAddr = 0;
-    *objSize = 0;
-
-    do
-    {
-        if((fd = open(path, O_RDONLY)) == -1)
-           continue;
-
-       if(fstat(fd, &stat_buf) == -1)
-           continue;
-
-        if (0 == (stat_buf.st_mode & S_IFREG)) 
-            continue;
-
-       /* Don't try to map an empty file, it fails now due to conformance
-        * stuff (PR 4611502).
-        */
-        if (0 == stat_buf.st_size) {
-            err = kErrorNone;
-            continue;
-        }
-
-       *objSize = stat_buf.st_size;
-
-        *objAddr = (vm_offset_t)mmap(NULL /* address */, *objSize,
-            PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE /* flags */,
-            fd, 0 /* offset */);
-
-       if ((void *)*objAddr == MAP_FAILED) {
-            *objAddr = 0;
-            *objSize = 0;
-           continue;
+       ToolError err;
+
+       if (offset != lseek(fd, offset, SEEK_SET)) {
+               err = kErrorDiskFull;
+       } else {
+               err = kErrorNone;
+       }
+
+       if (kErrorNone != err) {
+               perror("couldn't write output");
        }
 
-       err = kErrorNone;
+       return err;
+}
+
+/*********************************************************************
+*********************************************************************/
+__private_extern__ ToolError
+readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize)
+{
+       ToolError err = kErrorFileAccess;
+       int fd;
+       struct stat stat_buf;
+
+       *objAddr = 0;
+       *objSize = 0;
+
+       do{
+               if ((fd = open(path, O_RDONLY)) == -1) {
+                       continue;
+               }
+
+               if (fstat(fd, &stat_buf) == -1) {
+                       continue;
+               }
+
+               if (0 == (stat_buf.st_mode & S_IFREG)) {
+                       continue;
+               }
+
+               /* Don't try to map an empty file, it fails now due to conformance
+                * stuff (PR 4611502).
+                */
+               if (0 == stat_buf.st_size) {
+                       err = kErrorNone;
+                       continue;
+               }
 
-    } while( false );
+               *objSize = stat_buf.st_size;
 
-    if (-1 != fd)
-    {
-        close(fd);
-    }
-    if (kErrorNone != err)
-    {
-        fprintf(stderr, "couldn't read %s: %s\n", path, strerror(errno));
-    }
+               *objAddr = (vm_offset_t)mmap(NULL /* address */, *objSize,
+                   PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE /* flags */,
+                   fd, 0 /* offset */);
 
-    return( err );
+               if ((void *)*objAddr == MAP_FAILED) {
+                       *objAddr = 0;
+                       *objSize = 0;
+                       continue;
+               }
+
+               err = kErrorNone;
+       } while (false);
+
+       if (-1 != fd) {
+               close(fd);
+       }
+       if (kErrorNone != err) {
+               fprintf(stderr, "couldn't read %s: %s\n", path, strerror(errno));
+       }
+
+       return err;
 }
 
 
 enum { kExported = 0x00000001, kObsolete = 0x00000002 };
 
 struct symbol {
-    char * name;
-    unsigned int name_len;
-    char * indirect;
-    unsigned int indirect_len;
-    unsigned int flags;
-    struct symbol * list;
-    unsigned int list_count;
+       char * name;
+       unsigned int name_len;
+       char * indirect;
+       unsigned int indirect_len;
+       unsigned int flags;
+       struct symbol * list;
+       unsigned int list_count;
 };
 
-static bool issymchar( char c )
+static bool
+issymchar( char c )
 {
-    return ((c > ' ') && (c <= '~') && (c != ':') && (c != '#'));
+       return (c > ' ') && (c <= '~') && (c != ':') && (c != '#');
 }
 
-static bool iswhitespace( char c )
+static bool
+iswhitespace( char c )
 {
-    return ((c == ' ') || (c == '\t'));
+       return (c == ' ') || (c == '\t');
 }
 
 /*
@@ -172,10 +199,10 @@ static bool iswhitespace( char c )
 static int
 qsort_cmp(const void * _left, const void * _right)
 {
-    struct symbol * left  = (struct symbol *) _left;
-    struct symbol * right = (struct symbol *) _right;
+       struct symbol * left  = (struct symbol *) _left;
+       struct symbol * right = (struct symbol *) _right;
 
-    return (strcmp(left->name, right->name));
+       return strcmp(left->name, right->name);
 }
 
 /*
@@ -185,728 +212,757 @@ qsort_cmp(const void * _left, const void * _right)
 static int
 bsearch_cmp( const void * _key, const void * _cmp)
 {
-    char * key = (char *)_key;
-    struct symbol * cmp = (struct symbol *) _cmp;
+       char * key = (char *)_key;
+       struct symbol * cmp = (struct symbol *) _cmp;
 
-    return(strcmp(key, cmp->name));
+       return strcmp(key, cmp->name);
 }
 
-struct bsearch_key
-{
-    char * name;
-    unsigned int name_len;
+struct bsearch_key {
+       char * name;
+       unsigned int name_len;
 };
 
 static int
 bsearch_cmp_prefix( const void * _key, const void * _cmp)
 {
-    struct bsearch_key * key = (struct bsearch_key *)_key;
-    struct symbol *      cmp = (struct symbol *) _cmp;
+       struct bsearch_key * key = (struct bsearch_key *)_key;
+       struct symbol *      cmp = (struct symbol *) _cmp;
 
-    return(strncmp(key->name, cmp->name, key->name_len));
+       return strncmp(key->name, cmp->name, key->name_len);
 }
 
 static uint32_t
 count_symbols(char * file, vm_size_t file_size)
 {
-    uint32_t nsyms = 0;
-    char *   scan;
-    char *   eol;
-    char *   next;
-
-    for (scan = file; true; scan = next) {
-
-        eol = memchr(scan, '\n', file_size - (scan - file));
-        if (eol == NULL) {
-            break;
-        }
-        next = eol + 1;
-
-       /* Skip empty lines.
-        */
-        if (eol == scan) {
-            continue;
-        }
-
-       /* Skip comment lines.
-        */
-        if (scan[0] == '#') {
-            continue;
-        }
-
-       /* Scan past any non-symbol characters at the beginning of the line. */
-        while ((scan < eol) && !issymchar(*scan)) {
-            scan++;
-        }
-
-       /* No symbol on line? Move along.
-        */
-        if (scan == eol) {
-            continue;
-        }
-
-       /* Skip symbols starting with '.'.
-        */
-        if (scan[0] == '.') {
-            continue;
-        }
-        nsyms++;
-    }
-    
-    return nsyms;
+       uint32_t nsyms = 0;
+       char *   scan;
+       char *   eol;
+       char *   next;
+
+       for (scan = file; true; scan = next) {
+               eol = memchr(scan, '\n', file_size - (scan - file));
+               if (eol == NULL) {
+                       break;
+               }
+               next = eol + 1;
+
+               /* Skip empty lines.
+                */
+               if (eol == scan) {
+                       continue;
+               }
+
+               /* Skip comment lines.
+                */
+               if (scan[0] == '#') {
+                       continue;
+               }
+
+               /* Scan past any non-symbol characters at the beginning of the line. */
+               while ((scan < eol) && !issymchar(*scan)) {
+                       scan++;
+               }
+
+               /* No symbol on line? Move along.
+                */
+               if (scan == eol) {
+                       continue;
+               }
+
+               /* Skip symbols starting with '.'.
+                */
+               if (scan[0] == '.') {
+                       continue;
+               }
+               nsyms++;
+       }
+
+       return nsyms;
 }
 
 static uint32_t
 store_symbols(char * file, vm_size_t file_size, struct symbol * symbols, uint32_t idx, uint32_t max_symbols)
 {
-    char *   scan;
-    char *   line;
-    char *   eol;
-    char *   next;
-
-    uint32_t strtabsize;
-
-    strtabsize = 0;
-
-    for (scan = file, line = file; true; scan = next, line = next) {
-
-        char *       name = NULL;
-        char *       name_term = NULL;
-        unsigned int name_len = 0;
-        char *       indirect = NULL;
-        char *       indirect_term = NULL;
-        unsigned int indirect_len = 0;
-        char *       option = NULL;
-        char *       option_term = NULL;
-        unsigned int option_len = 0;
-        char         optionstr[256];
-        boolean_t    obsolete = 0;
-
-        eol = memchr(scan, '\n', file_size - (scan - file));
-        if (eol == NULL) {
-            break;
-        }
-        next = eol + 1;
-
-       /* Skip empty lines.
-        */
-        if (eol == scan) {
-            continue;
-        }
-
-        *eol = '\0';
-
-       /* Skip comment lines.
-        */
-        if (scan[0] == '#') {
-            continue;
-        }
-
-       /* Scan past any non-symbol characters at the beginning of the line. */
-        while ((scan < eol) && !issymchar(*scan)) {
-            scan++;
-        }
-
-       /* No symbol on line? Move along.
-        */
-        if (scan == eol) {
-            continue;
-        }
-
-       /* Skip symbols starting with '.'.
-        */
-        if (scan[0] == '.') {
-            continue;
-        }
-
-        name = scan;
-
-       /* Find the end of the symbol.
-        */
-        while ((*scan != '\0') && issymchar(*scan)) {
-            scan++;
-        }
-
-       /* Note char past end of symbol.
-        */
-        name_term = scan;
-
-       /* Stored length must include the terminating nul char.
-        */
-        name_len = name_term - name + 1;
-
-       /* Now look for an indirect.
-        */
-        if (*scan != '\0') {
-            while ((*scan != '\0') && iswhitespace(*scan)) {
-                scan++;
-            }
-            if (*scan == ':') {
-                scan++;
-                while ((*scan != '\0') && iswhitespace(*scan)) {
-                    scan++;
-                }
-                if (issymchar(*scan)) {
-                    indirect = scan;
-
-                   /* Find the end of the symbol.
-                    */
-                    while ((*scan != '\0') && issymchar(*scan)) {
-                        scan++;
-                    }
-
-                   /* Note char past end of symbol.
-                    */
-                    indirect_term = scan;
-
-                   /* Stored length must include the terminating nul char.
-                    */
-                    indirect_len = indirect_term - indirect + 1;
-
-                } else if (*scan == '\0') {
-                   fprintf(stderr, "bad format in symbol line: %s\n", line);
-                   exit(1);
-               }
-            } else if (*scan != '\0' && *scan != '-') {
-                fprintf(stderr, "bad format in symbol line: %s\n", line);
-                exit(1);
-            }
-        }
-
-        /* Look for options.
-         */
-        if (*scan != '\0') {
-            while ((*scan != '\0') && iswhitespace(*scan)) {
-                scan++;
-            }
-
-            if (*scan == '-') {
-                scan++;
-
-                if (isalpha(*scan)) {
-                    option = scan;
-
-                   /* Find the end of the option.
-                    */
-                    while ((*scan != '\0') && isalpha(*scan)) {
-                        scan++;
-                    }
-
-                   /* Note char past end of option.
-                    */
-                    option_term = scan;
-                    option_len = option_term - option;
-
-                    if (option_len >= sizeof(optionstr)) {
-                        fprintf(stderr, "option too long in symbol line: %s\n", line);
-                        exit(1);
-                    }
-                    memcpy(optionstr, option, option_len);
-                    optionstr[option_len] = '\0';
-
-                    /* Find the option.
-                     */
-                    if (!strncmp(optionstr, "obsolete", option_len)) {
-                        obsolete = TRUE;
-                    }
-
-                } else if (*scan == '\0') {
-                   fprintf(stderr, "bad format in symbol line: %s\n", line);
-                   exit(1);
-               }
-
-            }
-
-        }
-
-        if(idx >= max_symbols) {
-            fprintf(stderr, "symbol[%d/%d] overflow: %s\n", idx, max_symbols, line);
-            exit(1);
-        }
-
-        *name_term = '\0';
-        if (indirect_term) {
-            *indirect_term = '\0';
-        }
-        
-        symbols[idx].name = name;
-        symbols[idx].name_len = name_len;
-        symbols[idx].indirect = indirect;
-        symbols[idx].indirect_len = indirect_len;
-        symbols[idx].flags = (obsolete) ? kObsolete : 0;
-
-        strtabsize += symbols[idx].name_len + symbols[idx].indirect_len;
-        idx++;
-    }
-
-    return strtabsize;
+       char *   scan;
+       char *   line;
+       char *   eol;
+       char *   next;
+
+       uint32_t strtabsize;
+
+       strtabsize = 0;
+
+       for (scan = file, line = file; true; scan = next, line = next) {
+               char *       name = NULL;
+               char *       name_term = NULL;
+               unsigned int name_len = 0;
+               char *       indirect = NULL;
+               char *       indirect_term = NULL;
+               unsigned int indirect_len = 0;
+               char *       option = NULL;
+               char *       option_term = NULL;
+               unsigned int option_len = 0;
+               char         optionstr[256];
+               boolean_t    obsolete = 0;
+
+               eol = memchr(scan, '\n', file_size - (scan - file));
+               if (eol == NULL) {
+                       break;
+               }
+               next = eol + 1;
+
+               /* Skip empty lines.
+                */
+               if (eol == scan) {
+                       continue;
+               }
+
+               *eol = '\0';
+
+               /* Skip comment lines.
+                */
+               if (scan[0] == '#') {
+                       continue;
+               }
+
+               /* Scan past any non-symbol characters at the beginning of the line. */
+               while ((scan < eol) && !issymchar(*scan)) {
+                       scan++;
+               }
+
+               /* No symbol on line? Move along.
+                */
+               if (scan == eol) {
+                       continue;
+               }
+
+               /* Skip symbols starting with '.'.
+                */
+               if (scan[0] == '.') {
+                       continue;
+               }
+
+               name = scan;
+
+               /* Find the end of the symbol.
+                */
+               while ((*scan != '\0') && issymchar(*scan)) {
+                       scan++;
+               }
+
+               /* Note char past end of symbol.
+                */
+               name_term = scan;
+
+               /* Stored length must include the terminating nul char.
+                */
+               name_len = name_term - name + 1;
+
+               /* Now look for an indirect.
+                */
+               if (*scan != '\0') {
+                       while ((*scan != '\0') && iswhitespace(*scan)) {
+                               scan++;
+                       }
+                       if (*scan == ':') {
+                               scan++;
+                               while ((*scan != '\0') && iswhitespace(*scan)) {
+                                       scan++;
+                               }
+                               if (issymchar(*scan)) {
+                                       indirect = scan;
+
+                                       /* Find the end of the symbol.
+                                        */
+                                       while ((*scan != '\0') && issymchar(*scan)) {
+                                               scan++;
+                                       }
+
+                                       /* Note char past end of symbol.
+                                        */
+                                       indirect_term = scan;
+
+                                       /* Stored length must include the terminating nul char.
+                                        */
+                                       indirect_len = indirect_term - indirect + 1;
+                               } else if (*scan == '\0') {
+                                       fprintf(stderr, "bad format in symbol line: %s\n", line);
+                                       exit(1);
+                               }
+                       } else if (*scan != '\0' && *scan != '-') {
+                               fprintf(stderr, "bad format in symbol line: %s\n", line);
+                               exit(1);
+                       }
+               }
+
+               /* Look for options.
+                */
+               if (*scan != '\0') {
+                       while ((*scan != '\0') && iswhitespace(*scan)) {
+                               scan++;
+                       }
+
+                       if (*scan == '-') {
+                               scan++;
+
+                               if (isalpha(*scan)) {
+                                       option = scan;
+
+                                       /* Find the end of the option.
+                                        */
+                                       while ((*scan != '\0') && isalpha(*scan)) {
+                                               scan++;
+                                       }
+
+                                       /* Note char past end of option.
+                                        */
+                                       option_term = scan;
+                                       option_len = option_term - option;
+
+                                       if (option_len >= sizeof(optionstr)) {
+                                               fprintf(stderr, "option too long in symbol line: %s\n", line);
+                                               exit(1);
+                                       }
+                                       memcpy(optionstr, option, option_len);
+                                       optionstr[option_len] = '\0';
+
+                                       /* Find the option.
+                                        */
+                                       if (!strncmp(optionstr, "obsolete", option_len)) {
+                                               obsolete = TRUE;
+                                       }
+                               } else if (*scan == '\0') {
+                                       fprintf(stderr, "bad format in symbol line: %s\n", line);
+                                       exit(1);
+                               }
+                       }
+               }
+
+               if (idx >= max_symbols) {
+                       fprintf(stderr, "symbol[%d/%d] overflow: %s\n", idx, max_symbols, line);
+                       exit(1);
+               }
+
+               *name_term = '\0';
+               if (indirect_term) {
+                       *indirect_term = '\0';
+               }
+
+               symbols[idx].name = name;
+               symbols[idx].name_len = name_len;
+               symbols[idx].indirect = indirect;
+               symbols[idx].indirect_len = indirect_len;
+               symbols[idx].flags = (obsolete) ? kObsolete : 0;
+
+               strtabsize += symbols[idx].name_len + symbols[idx].indirect_len;
+               idx++;
+       }
+
+       return strtabsize;
+}
+
+static const NXArchInfo *
+lookup_arch(const char *archstring)
+{
+       /*
+        * As new architectures are supported by xnu, add a mapping function
+        * without relying on host libraries.
+        */
+       static const NXArchInfo archlist[] = {
+               { "x86_64", 0x01000007 /* CPU_TYPE_X86_64 */, 3 /* CPU_SUBTYPE_X86_64_ALL */, NX_LittleEndian, NULL },
+               { "x86_64h", 0x01000007 /* CPU_TYPE_X86_64 */, 8 /* CPU_SUBTYPE_X86_64_H */, NX_LittleEndian, NULL },
+               { "armv7", 12 /* CPU_TYPE_ARM */, 9 /* CPU_SUBTYPE_ARM_V7 */, NX_LittleEndian, NULL },
+               { "armv7s", 12 /* CPU_TYPE_ARM */, 11 /* CPU_SUBTYPE_ARM_V7S */, NX_LittleEndian, NULL },
+               { "armv7k", 12 /* CPU_TYPE_ARM */, 12 /* CPU_SUBTYPE_ARM_V7K */, NX_LittleEndian, NULL },
+               { "arm64", 0x0100000c /* CPU_TYPE_ARM64 */, 0 /* CPU_SUBTYPE_ARM64_ALL */, NX_LittleEndian, NULL },
+       };
+       unsigned long i;
+
+       for (i = 0; i < sizeof(archlist) / sizeof(archlist[0]); i++) {
+               if (0 == strcmp(archstring, archlist[i].name)) {
+                       return &archlist[i];
+               }
+       }
+
+       return NULL;
 }
 
 /*********************************************************************
 *********************************************************************/
-int main(int argc, char * argv[])
+int
+main(int argc, char * argv[])
 {
-    ToolError  err;
-    int                        i, fd;
-    const char *       output_name = NULL;
-    uint32_t           zero = 0, num_files = 0;
-    uint32_t           filenum;
-    uint32_t           strx, strtabsize, strtabpad;
-    struct symbol *    import_symbols;
-    struct symbol *    export_symbols;
-    uint32_t           num_import_syms, num_export_syms;
-    uint32_t           result_count, num_removed_syms;
-    uint32_t           import_idx, export_idx;
-    const NXArchInfo * host_arch;
-    const NXArchInfo * target_arch;
-    boolean_t          require_imports = true;
-    boolean_t          diff = false;
-
-
-    struct file {
-        vm_offset_t  mapped;
-        vm_size_t    mapped_size;
-       uint32_t     nsyms;
-       boolean_t    import;
-       const char * path;
-    };
-    struct file files[64];
-    
-    host_arch = NXGetLocalArchInfo();
-    target_arch = host_arch;
-
-    for( i = 1; i < argc; i += 2)
-    {
-       boolean_t import;
-
-        if (!strcmp("-sect", argv[i]))
-        {
-           require_imports = false;
-           i--;
-           continue;
-        }
-        if (!strcmp("-diff", argv[i]))
-        {
-           require_imports = false;
-           diff = true;
-           i--;
-           continue;
-        }
-
-       if (i == (argc - 1))
-       {
-           fprintf(stderr, "bad arguments: %s\n", argv[i]);
-           exit(1);
+       ToolError   err;
+       int                 i, fd;
+       const char *        output_name = NULL;
+       uint32_t            zero = 0, num_files = 0;
+       uint32_t            filenum;
+       uint32_t            strx, strtabsize, strtabpad;
+       struct symbol *     import_symbols;
+       struct symbol *     export_symbols;
+       uint32_t            num_import_syms, num_export_syms;
+       uint32_t            result_count, num_removed_syms;
+       uint32_t            import_idx, export_idx;
+       const NXArchInfo *  host_arch;
+       const NXArchInfo *  target_arch;
+       boolean_t           require_imports = true;
+       boolean_t           diff = false;
+
+
+       struct file {
+               vm_offset_t  mapped;
+               vm_size_t    mapped_size;
+               uint32_t     nsyms;
+               boolean_t    import;
+               const char * path;
+       };
+       struct file files[64];
+
+       host_arch = NXGetLocalArchInfo();
+       target_arch = host_arch;
+
+       for (i = 1; i < argc; i += 2) {
+               boolean_t import;
+
+               if (!strcmp("-sect", argv[i])) {
+                       require_imports = false;
+                       i--;
+                       continue;
+               }
+               if (!strcmp("-diff", argv[i])) {
+                       require_imports = false;
+                       diff = true;
+                       i--;
+                       continue;
+               }
+
+               if (i == (argc - 1)) {
+                       fprintf(stderr, "bad arguments: %s\n", argv[i]);
+                       exit(1);
+               }
+
+               if (!strcmp("-arch", argv[i])) {
+                       target_arch = lookup_arch(argv[i + 1]);
+                       if (!target_arch) {
+                               fprintf(stderr, "unknown architecture name: %s\n", argv[i + 1]);
+                               exit(1);
+                       }
+                       continue;
+               }
+               if (!strcmp("-output", argv[i])) {
+                       output_name = argv[i + 1];
+                       continue;
+               }
+
+               if (!strcmp("-import", argv[i])) {
+                       import = true;
+               } else if (!strcmp("-export", argv[i])) {
+                       import = false;
+               } else {
+                       fprintf(stderr, "unknown option: %s\n", argv[i]);
+                       exit(1);
+               }
+
+               err = readFile(argv[i + 1], &files[num_files].mapped, &files[num_files].mapped_size);
+               if (kErrorNone != err) {
+                       exit(1);
+               }
+
+               if (files[num_files].mapped && files[num_files].mapped_size) {
+                       files[num_files].import = import;
+                       files[num_files].path   = argv[i + 1];
+                       num_files++;
+               }
        }
 
-        if (!strcmp("-arch", argv[i]))
-        {
-            target_arch = NXGetArchInfoFromName(argv[i + 1]);
-           if (!target_arch)
-           {
-               fprintf(stderr, "unknown architecture name: %s\n", argv[i+1]);
+       if (!output_name) {
+               fprintf(stderr, "no output file\n");
                exit(1);
-           }
-            continue;
-        }
-        if (!strcmp("-output", argv[i]))
-        {
-           output_name = argv[i+1];
-            continue;
-        }
-
-        if (!strcmp("-import", argv[i]))
-           import = true;
-       else if (!strcmp("-export", argv[i]))
-           import = false;
-       else
-       {
-           fprintf(stderr, "unknown option: %s\n", argv[i]);
-           exit(1);
        }
 
-        err = readFile(argv[i+1], &files[num_files].mapped, &files[num_files].mapped_size);
-        if (kErrorNone != err)
-            exit(1);
+       num_import_syms = 0;
+       num_export_syms = 0;
+       for (filenum = 0; filenum < num_files; filenum++) {
+               files[filenum].nsyms = count_symbols((char *) files[filenum].mapped, files[filenum].mapped_size);
+               if (files[filenum].import) {
+                       num_import_syms += files[filenum].nsyms;
+               } else {
+                       num_export_syms += files[filenum].nsyms;
+               }
+       }
 
-        if (files[num_files].mapped && files[num_files].mapped_size)
-       {
-           files[num_files].import = import;
-           files[num_files].path   = argv[i+1];
-            num_files++;
+       import_symbols = calloc(num_import_syms, sizeof(struct symbol));
+       export_symbols = calloc(num_export_syms, sizeof(struct symbol));
+
+       import_idx = 0;
+       export_idx = 0;
+
+       for (filenum = 0; filenum < num_files; filenum++) {
+               if (files[filenum].import) {
+                       store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
+                           import_symbols, import_idx, num_import_syms);
+                       import_idx += files[filenum].nsyms;
+               } else {
+                       store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
+                           export_symbols, export_idx, num_export_syms);
+                       export_idx += files[filenum].nsyms;
+               }
+               if (false && !files[filenum].nsyms) {
+                       fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path);
+               }
        }
-    }
-
-    if (!output_name)
-    {
-       fprintf(stderr, "no output file\n");
-       exit(1);
-    }
-
-    num_import_syms = 0;
-    num_export_syms = 0;
-    for (filenum = 0; filenum < num_files; filenum++)
-    {
-        files[filenum].nsyms = count_symbols((char *) files[filenum].mapped, files[filenum].mapped_size);
-       if (files[filenum].import)
-           num_import_syms += files[filenum].nsyms;
-       else
-           num_export_syms += files[filenum].nsyms;
-    }
-    if (!num_export_syms)
-    {
-       fprintf(stderr, "no export names\n");
-       exit(1);
-    }
-
-    import_symbols = calloc(num_import_syms, sizeof(struct symbol));
-    export_symbols = calloc(num_export_syms, sizeof(struct symbol));
-
-    import_idx = 0;
-    export_idx = 0;
-
-    for (filenum = 0; filenum < num_files; filenum++)
-    {
-       if (files[filenum].import)
-       {
-           store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
-                                       import_symbols, import_idx, num_import_syms);
-           import_idx += files[filenum].nsyms;
+
+
+       qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp);
+       qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp);
+
+       result_count = 0;
+       num_removed_syms = 0;
+       strtabsize = 4;
+       if (num_import_syms) {
+               for (export_idx = 0; export_idx < num_export_syms; export_idx++) {
+                       struct symbol * result;
+                       char * name;
+                       size_t len;
+                       boolean_t wild;
+
+                       name = export_symbols[export_idx].indirect;
+                       len  = export_symbols[export_idx].indirect_len;
+                       if (!name) {
+                               name = export_symbols[export_idx].name;
+                               len  = export_symbols[export_idx].name_len;
+                       }
+                       wild = ((len > 2) && ('*' == name[len -= 2]));
+                       if (wild) {
+                               struct bsearch_key key;
+                               key.name = name;
+                               key.name_len = len;
+                               result = bsearch(&key, import_symbols,
+                                   num_import_syms, sizeof(struct symbol), &bsearch_cmp_prefix);
+
+                               if (result) {
+                                       struct symbol * first;
+                                       struct symbol * last;
+
+                                       strtabsize += (result->name_len + result->indirect_len);
+
+                                       first = result;
+                                       while (--first >= &import_symbols[0]) {
+                                               if (bsearch_cmp_prefix(&key, first)) {
+                                                       break;
+                                               }
+                                               strtabsize += (first->name_len + first->indirect_len);
+                                       }
+                                       first++;
+
+                                       last = result;
+                                       while (++last < (&import_symbols[0] + num_import_syms)) {
+                                               if (bsearch_cmp_prefix(&key, last)) {
+                                                       break;
+                                               }
+                                               strtabsize += (last->name_len + last->indirect_len);
+                                       }
+                                       result_count += last - first;
+                                       result = first;
+                                       export_symbols[export_idx].list = first;
+                                       export_symbols[export_idx].list_count = last - first;
+                                       export_symbols[export_idx].flags |= kExported;
+                               }
+                       } else {
+                               result = bsearch(name, import_symbols,
+                                   num_import_syms, sizeof(struct symbol), &bsearch_cmp);
+                       }
+
+                       if (!result && require_imports) {
+                               int status;
+                               char * demangled_result =
+                                   __cxa_demangle(export_symbols[export_idx].name + 1, NULL, NULL, &status);
+                               fprintf(stderr, "exported name not in import list: %s\n",
+                                   demangled_result ? demangled_result : export_symbols[export_idx].name);
+//             fprintf(stderr, "                                : %s\n", export_symbols[export_idx].name);
+                               if (demangled_result) {
+                                       free(demangled_result);
+                               }
+                               num_removed_syms++;
+                       }
+                       if (diff) {
+                               if (!result) {
+                                       result = &export_symbols[export_idx];
+                               } else {
+                                       result = NULL;
+                               }
+                       }
+                       if (result && !wild) {
+                               export_symbols[export_idx].flags |= kExported;
+                               strtabsize += (export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len);
+                               result_count++;
+                               export_symbols[export_idx].list = &export_symbols[export_idx];
+                               export_symbols[export_idx].list_count = 1;
+                       }
+               }
        }
-       else
-       {
-           store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
-                                       export_symbols, export_idx, num_export_syms);
-           export_idx += files[filenum].nsyms;
+       strtabpad = (strtabsize + 3) & ~3;
+
+       if (require_imports && num_removed_syms) {
+               err = kError;
+               goto finish;
        }
-       if (false && !files[filenum].nsyms)
-       {
-           fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path);
+
+       fd = open(output_name, O_WRONLY | O_CREAT | O_TRUNC, 0755);
+       if (-1 == fd) {
+               perror("couldn't write output");
+               err = kErrorFileAccess;
+               goto finish;
        }
-    }
-
-
-    qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp);
-    qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp);
-
-    result_count = 0;
-    num_removed_syms = 0;
-    strtabsize = 4;
-    if (num_import_syms)
-    {
-       for (export_idx = 0; export_idx < num_export_syms; export_idx++)
-       {
-           struct symbol * result;
-           char * name;
-           size_t len;
-           boolean_t wild;
-
-           name = export_symbols[export_idx].indirect;
-           len  = export_symbols[export_idx].indirect_len;
-           if (!name)
-           {
-               name = export_symbols[export_idx].name;
-               len  = export_symbols[export_idx].name_len;
-           }
-           wild = ((len > 2) && ('*' == name[len-=2]));
-           if (wild)
-           {
-               struct bsearch_key key;
-               key.name = name;
-               key.name_len = len;
-               result = bsearch(&key, import_symbols, 
-                                   num_import_syms, sizeof(struct symbol), &bsearch_cmp_prefix);
 
-               if (result)
-               {
-                   struct symbol * first;
-                   struct symbol * last;
-
-                   strtabsize += (result->name_len + result->indirect_len);
-
-                   first = result;
-                   while (--first >= &import_symbols[0])
-                   {
-                       if (bsearch_cmp_prefix(&key, first))
-                           break;
-                       strtabsize += (first->name_len + first->indirect_len);
-                   }
-                   first++;
-
-                   last = result;
-                   while (++last < (&import_symbols[0] + num_import_syms))
-                   {
-                       if (bsearch_cmp_prefix(&key, last))
-                           break;
-                       strtabsize += (last->name_len + last->indirect_len);
-                   }
-                   result_count += last - first;
-                   result = first;
-                   export_symbols[export_idx].list = first;
-                   export_symbols[export_idx].list_count = last - first;
-                   export_symbols[export_idx].flags |= kExported;
-               }
-           }
-           else
-               result = bsearch(name, import_symbols, 
-                                   num_import_syms, sizeof(struct symbol), &bsearch_cmp);
+       struct symtab_command symcmd;
+       struct uuid_command uuidcmd;
+       off_t  symsoffset;
+
+       symcmd.cmd          = LC_SYMTAB;
+       symcmd.cmdsize      = sizeof(symcmd);
+       symcmd.nsyms        = result_count;
+       symcmd.strsize      = strtabpad;
+
+       uuidcmd.cmd         = LC_UUID;
+       uuidcmd.cmdsize     = sizeof(uuidcmd);
+       uuid_generate(uuidcmd.uuid);
+
+       if (CPU_ARCH_ABI64 & target_arch->cputype) {
+               struct mach_header_64     hdr;
+               struct segment_command_64 segcmd;
+
+               hdr.magic       = MH_MAGIC_64;
+               hdr.cputype     = target_arch->cputype;
+               hdr.cpusubtype  = target_arch->cpusubtype;
+               hdr.filetype    = MH_KEXT_BUNDLE;
+               hdr.ncmds       = 3;
+               hdr.sizeofcmds  = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd);
+               hdr.flags       = MH_INCRLINK;
+               symsoffset      = mach_vm_round_page(hdr.sizeofcmds);
+
+               segcmd.cmd      = LC_SEGMENT_64;
+               segcmd.cmdsize  = sizeof(segcmd);
+               strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname));
+               segcmd.vmaddr   = 0;
+               segcmd.vmsize   = result_count * sizeof(struct nlist_64) + strtabpad;
+               segcmd.fileoff  = symsoffset;
+               segcmd.filesize = segcmd.vmsize;
+               segcmd.maxprot  = PROT_READ;
+               segcmd.initprot = PROT_READ;
+               segcmd.nsects   = 0;
+               segcmd.flags    = SG_NORELOC;
+
+               symcmd.symoff   = symsoffset;
+               symcmd.stroff   = result_count * sizeof(struct nlist_64)
+                   + symcmd.symoff;
+
+               if (target_arch->byteorder != host_arch->byteorder) {
+                       swap_mach_header_64(&hdr, target_arch->byteorder);
+                       swap_segment_command_64(&segcmd, target_arch->byteorder);
+               }
+               err = writeFile(fd, &hdr, sizeof(hdr));
+               if (kErrorNone != err) {
+                       goto finish;
+               }
+               err = writeFile(fd, &segcmd, sizeof(segcmd));
+       } else {
+               struct mach_header     hdr;
+               struct segment_command segcmd;
+
+               hdr.magic       = MH_MAGIC;
+               hdr.cputype     = target_arch->cputype;
+               hdr.cpusubtype  = target_arch->cpusubtype;
+               hdr.filetype    = MH_KEXT_BUNDLE;
+               hdr.ncmds       = 3;
+               hdr.sizeofcmds  = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd);
+               hdr.flags       = MH_INCRLINK;
+               symsoffset      = mach_vm_round_page(hdr.sizeofcmds);
+
+               segcmd.cmd      = LC_SEGMENT;
+               segcmd.cmdsize  = sizeof(segcmd);
+               strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname));
+               segcmd.vmaddr   = 0;
+               segcmd.vmsize   = result_count * sizeof(struct nlist) + strtabpad;
+               segcmd.fileoff  = symsoffset;
+               segcmd.filesize = segcmd.vmsize;
+               segcmd.maxprot  = PROT_READ;
+               segcmd.initprot = PROT_READ;
+               segcmd.nsects   = 0;
+               segcmd.flags    = SG_NORELOC;
+
+               symcmd.symoff   = symsoffset;
+               symcmd.stroff   = result_count * sizeof(struct nlist)
+                   + symcmd.symoff;
+
+               if (target_arch->byteorder != host_arch->byteorder) {
+                       swap_mach_header(&hdr, target_arch->byteorder);
+                       swap_segment_command(&segcmd, target_arch->byteorder);
+               }
+               err = writeFile(fd, &hdr, sizeof(hdr));
+               if (kErrorNone != err) {
+                       goto finish;
+               }
+               err = writeFile(fd, &segcmd, sizeof(segcmd));
+       }
 
-           if (!result && require_imports)
-           {
-               int status;
-               char * demangled_result = 
-                       __cxa_demangle(export_symbols[export_idx].name + 1, NULL, NULL, &status);
-               fprintf(stderr, "exported name not in import list: %s\n",
-                                       demangled_result ? demangled_result : export_symbols[export_idx].name);
-//             fprintf(stderr, "                                : %s\n", export_symbols[export_idx].name);
-               if (demangled_result) {
-                       free(demangled_result);
-               }
-               num_removed_syms++;
-           }
-           if (diff)
-           {
-               if (!result)
-                   result = &export_symbols[export_idx];
-               else
-                   result = NULL;
-           }
-           if (result && !wild)
-           {
-               export_symbols[export_idx].flags |= kExported;
-               strtabsize += (export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len);
-               result_count++;
-               export_symbols[export_idx].list = &export_symbols[export_idx];
-               export_symbols[export_idx].list_count = 1;
-           }
+       if (kErrorNone != err) {
+               goto finish;
        }
-    }
-    strtabpad = (strtabsize + 3) & ~3;
-
-    if (require_imports && num_removed_syms)
-    {
-       err = kError;
-       goto finish;
-    }
-
-    fd = open(output_name, O_WRONLY|O_CREAT|O_TRUNC, 0755);
-    if (-1 == fd)
-    {
-       perror("couldn't write output");
-       err = kErrorFileAccess;
-       goto finish;
-    }
-
-    struct symtab_command symcmd;
-    struct uuid_command uuidcmd;
-
-    symcmd.cmd         = LC_SYMTAB;
-    symcmd.cmdsize     = sizeof(symcmd);
-    symcmd.symoff      = sizeof(symcmd) + sizeof(uuidcmd);
-    symcmd.nsyms       = result_count;
-    symcmd.strsize     = strtabpad;
-
-    uuidcmd.cmd         = LC_UUID;
-    uuidcmd.cmdsize     = sizeof(uuidcmd);
-    uuid_generate(uuidcmd.uuid);
-
-    if (CPU_ARCH_ABI64 & target_arch->cputype)
-    {
-       struct mach_header_64 hdr;
-       hdr.magic       = MH_MAGIC_64;
-       hdr.cputype     = target_arch->cputype;
-       hdr.cpusubtype  = target_arch->cpusubtype;
-       hdr.filetype    = MH_KEXT_BUNDLE;
-       hdr.ncmds       = 2;
-       hdr.sizeofcmds  = sizeof(symcmd) + sizeof(uuidcmd);
-       hdr.flags       = MH_INCRLINK;
-
-       symcmd.symoff   += sizeof(hdr);
-       symcmd.stroff   = result_count * sizeof(struct nlist_64) 
-                               + symcmd.symoff;
-
-       if (target_arch->byteorder != host_arch->byteorder)
-           swap_mach_header_64(&hdr, target_arch->byteorder);
-       err = writeFile(fd, &hdr, sizeof(hdr));
-    }
-    else
-    {
-       struct mach_header    hdr;
-       hdr.magic       = MH_MAGIC;
-       hdr.cputype     = target_arch->cputype;
-       hdr.cpusubtype  = target_arch->cpusubtype;
-       hdr.filetype    = (target_arch->cputype == CPU_TYPE_I386) ? MH_OBJECT : MH_KEXT_BUNDLE;
-       hdr.ncmds       = 2;
-       hdr.sizeofcmds  = sizeof(symcmd) + sizeof(uuidcmd);
-       hdr.flags       = MH_INCRLINK;
-
-       symcmd.symoff   += sizeof(hdr);
-       symcmd.stroff   = result_count * sizeof(struct nlist) 
-                               + symcmd.symoff;
-
-       if (target_arch->byteorder != host_arch->byteorder)
-           swap_mach_header(&hdr, target_arch->byteorder);
-       err = writeFile(fd, &hdr, sizeof(hdr));
-    }
-
-    if (kErrorNone != err)
-       goto finish;
-
-    if (target_arch->byteorder != host_arch->byteorder) {
-        swap_symtab_command(&symcmd, target_arch->byteorder);
-        swap_uuid_command(&uuidcmd, target_arch->byteorder);
-    }
-    err = writeFile(fd, &symcmd, sizeof(symcmd));
-    if (kErrorNone != err)
-       goto finish;
-    err = writeFile(fd, &uuidcmd, sizeof(uuidcmd));
-    if (kErrorNone != err)
-        goto finish;
-
-    strx = 4;
-    for (export_idx = 0; export_idx < num_export_syms; export_idx++)
-    {
-       if (!export_symbols[export_idx].name)
-           continue;
-       if (!(kExported & export_symbols[export_idx].flags))
-           continue;
-
-       if (export_idx
-         && export_symbols[export_idx - 1].name
-         && !strcmp(export_symbols[export_idx - 1].name, export_symbols[export_idx].name))
-       {
-           fprintf(stderr, "duplicate export: %s\n", export_symbols[export_idx - 1].name);
-           err = kErrorDuplicate;
-           goto finish;
+
+       if (target_arch->byteorder != host_arch->byteorder) {
+               swap_symtab_command(&symcmd, target_arch->byteorder);
+               swap_uuid_command(&uuidcmd, target_arch->byteorder);
+       }
+       err = writeFile(fd, &symcmd, sizeof(symcmd));
+       if (kErrorNone != err) {
+               goto finish;
+       }
+       err = writeFile(fd, &uuidcmd, sizeof(uuidcmd));
+       if (kErrorNone != err) {
+               goto finish;
        }
 
-       for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++)
-       {
-
-           if (export_symbols[export_idx].list != &export_symbols[export_idx])
-           {
-               printf("wild: %s, %s\n", export_symbols[export_idx].name, 
-                       export_symbols[export_idx].list[import_idx].name);
-           }
-           if (CPU_ARCH_ABI64 & target_arch->cputype)
-           {
-               struct nlist_64 nl;
-
-               nl.n_sect  = 0;
-                nl.n_desc  = 0;
-               nl.n_un.n_strx = strx;
-               strx += export_symbols[export_idx].list[import_idx].name_len;
-                
-                if (export_symbols[export_idx].flags & kObsolete) {
-                    nl.n_desc |= N_DESC_DISCARDED;
-                }
-
-               if (export_symbols[export_idx].list[import_idx].indirect)
-               {
-                   nl.n_type  = N_INDR | N_EXT;
-                   nl.n_value = strx;
-                   strx += export_symbols[export_idx].list[import_idx].indirect_len;
-               }
-               else
-               {
-                   nl.n_type  = N_UNDF | N_EXT;
-                   nl.n_value = 0;
-               }
-
-               if (target_arch->byteorder != host_arch->byteorder)
-                   swap_nlist_64(&nl, 1, target_arch->byteorder);
-
-               err = writeFile(fd, &nl, sizeof(nl));
-           }
-           else
-           {
-               struct nlist nl;
-
-               nl.n_sect  = 0;
-               nl.n_desc  = 0;
-               nl.n_un.n_strx = strx;
-               strx += export_symbols[export_idx].list[import_idx].name_len;
-                if (export_symbols[export_idx].flags & kObsolete) {
-                    nl.n_desc |= N_DESC_DISCARDED;
-                }
-
-               if (export_symbols[export_idx].list[import_idx].indirect)
-               {
-                   nl.n_type  = N_INDR | N_EXT;
-                   nl.n_value = strx;
-                   strx += export_symbols[export_idx].list[import_idx].indirect_len;
-               }
-               else
-               {
-                   nl.n_type  = N_UNDF | N_EXT;
-                   nl.n_value = 0;
-               }
-
-               if (target_arch->byteorder != host_arch->byteorder)
-                   swap_nlist(&nl, 1, target_arch->byteorder);
-
-               err = writeFile(fd, &nl, sizeof(nl));
-           }
+       err = seekFile(fd, symsoffset);
+       if (kErrorNone != err) {
+               goto finish;
        }
 
-       if (kErrorNone != err)
-           goto finish;
-    }
-
-    strx = sizeof(uint32_t);
-    err = writeFile(fd, &zero, strx);
-    if (kErrorNone != err)
-       goto finish;
-
-    for (export_idx = 0; export_idx < num_export_syms; export_idx++)
-    {
-       if (!export_symbols[export_idx].name)
-           continue;
-
-       for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++)
-       {
-           err = writeFile(fd, export_symbols[export_idx].list[import_idx].name, 
-                       export_symbols[export_idx].list[import_idx].name_len);
-           if (kErrorNone != err)
+       strx = 4;
+       for (export_idx = 0; export_idx < num_export_syms; export_idx++) {
+               if (!export_symbols[export_idx].name) {
+                       continue;
+               }
+               if (!(kExported & export_symbols[export_idx].flags)) {
+                       continue;
+               }
+
+               if (export_idx
+                   && export_symbols[export_idx - 1].name
+                   && !strcmp(export_symbols[export_idx - 1].name, export_symbols[export_idx].name)) {
+                       fprintf(stderr, "duplicate export: %s\n", export_symbols[export_idx - 1].name);
+                       err = kErrorDuplicate;
+                       goto finish;
+               }
+
+               for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) {
+                       if (export_symbols[export_idx].list != &export_symbols[export_idx]) {
+                               printf("wild: %s, %s\n", export_symbols[export_idx].name,
+                                   export_symbols[export_idx].list[import_idx].name);
+                       }
+                       if (CPU_ARCH_ABI64 & target_arch->cputype) {
+                               struct nlist_64 nl;
+
+                               nl.n_sect  = 0;
+                               nl.n_desc  = 0;
+                               nl.n_un.n_strx = strx;
+                               strx += export_symbols[export_idx].list[import_idx].name_len;
+
+                               if (export_symbols[export_idx].flags & kObsolete) {
+                                       nl.n_desc |= N_DESC_DISCARDED;
+                               }
+
+                               if (export_symbols[export_idx].list[import_idx].indirect) {
+                                       nl.n_type  = N_INDR | N_EXT;
+                                       nl.n_value = strx;
+                                       strx += export_symbols[export_idx].list[import_idx].indirect_len;
+                               } else {
+                                       nl.n_type  = N_UNDF | N_EXT;
+                                       nl.n_value = 0;
+                               }
+
+                               if (target_arch->byteorder != host_arch->byteorder) {
+                                       swap_nlist_64(&nl, 1, target_arch->byteorder);
+                               }
+
+                               err = writeFile(fd, &nl, sizeof(nl));
+                       } else {
+                               struct nlist nl;
+
+                               nl.n_sect  = 0;
+                               nl.n_desc  = 0;
+                               nl.n_un.n_strx = strx;
+                               strx += export_symbols[export_idx].list[import_idx].name_len;
+
+                               if (export_symbols[export_idx].flags & kObsolete) {
+                                       nl.n_desc |= N_DESC_DISCARDED;
+                               }
+
+                               if (export_symbols[export_idx].list[import_idx].indirect) {
+                                       nl.n_type  = N_INDR | N_EXT;
+                                       nl.n_value = strx;
+                                       strx += export_symbols[export_idx].list[import_idx].indirect_len;
+                               } else {
+                                       nl.n_type  = N_UNDF | N_EXT;
+                                       nl.n_value = 0;
+                               }
+
+                               if (target_arch->byteorder != host_arch->byteorder) {
+                                       swap_nlist(&nl, 1, target_arch->byteorder);
+                               }
+
+                               err = writeFile(fd, &nl, sizeof(nl));
+                       }
+               }
+
+               if (kErrorNone != err) {
+                       goto finish;
+               }
+       }
+
+       strx = sizeof(uint32_t);
+       err = writeFile(fd, &zero, strx);
+       if (kErrorNone != err) {
+               goto finish;
+       }
+
+       for (export_idx = 0; export_idx < num_export_syms; export_idx++) {
+               if (!export_symbols[export_idx].name) {
+                       continue;
+               }
+
+               for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) {
+                       err = writeFile(fd, export_symbols[export_idx].list[import_idx].name,
+                           export_symbols[export_idx].list[import_idx].name_len);
+                       if (kErrorNone != err) {
+                               goto finish;
+                       }
+                       if (export_symbols[export_idx].list[import_idx].indirect) {
+                               err = writeFile(fd, export_symbols[export_idx].list[import_idx].indirect,
+                                   export_symbols[export_idx].list[import_idx].indirect_len);
+                               if (kErrorNone != err) {
+                                       goto finish;
+                               }
+                       }
+               }
+       }
+
+       err = writeFile(fd, &zero, strtabpad - strtabsize);
+       if (kErrorNone != err) {
                goto finish;
-           if (export_symbols[export_idx].list[import_idx].indirect)
-           {
-               err = writeFile(fd, export_symbols[export_idx].list[import_idx].indirect, 
-                           export_symbols[export_idx].list[import_idx].indirect_len);
-               if (kErrorNone != err)
-                   goto finish;
-           }
        }
-    }
 
-    err = writeFile(fd, &zero, strtabpad - strtabsize);
-    if (kErrorNone != err)
-       goto finish;
-       
-    close(fd);
+       close(fd);
 
 
 finish:
-    for (filenum = 0; filenum < num_files; filenum++) {
-        // unmap file
-        if (files[filenum].mapped_size)
-        {
-            munmap((caddr_t)files[filenum].mapped, files[filenum].mapped_size);
-            files[filenum].mapped     = 0;
-            files[filenum].mapped_size = 0;
-        }
-
-    }
-
-    if (kErrorNone != err)
-    {
-       if (output_name)
-           unlink(output_name);
-        exit(1);
-    }
-    else
-        exit(0);
-    return(0);
-}
+       for (filenum = 0; filenum < num_files; filenum++) {
+               // unmap file
+               if (files[filenum].mapped_size) {
+                       munmap((caddr_t)files[filenum].mapped, files[filenum].mapped_size);
+                       files[filenum].mapped     = 0;
+                       files[filenum].mapped_size = 0;
+               }
+       }
 
+       if (kErrorNone != err) {
+               if (output_name && strncmp(output_name, "/dev/", 5)) {
+                       unlink(output_name);
+               }
+               exit(1);
+       } else {
+               exit(0);
+       }
+       return 0;
+}