--- /dev/null	2007-01-06 13:50:40.000000000 +0100
+++ output/outmacho.c	2006-02-02 22:50:47.000000000 +0100
@@ -0,0 +1,1319 @@
+/* outmacho.c	output routines for the Netwide Assembler to produce
+ *		NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X object files
+ *
+ * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
+ * Julian Hall. All rights reserved. The software is
+ * redistributable under the licence given in the file "Licence"
+ * distributed in the NASM archive.
+ */
+
+/* Most of this file is, like Mach-O itself, based on a.out. For more
+ * guidelines see outaout.c.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "outform.h"
+
+#if defined(OF_MACHO)
+
+/* Mach-O in-file header structure sizes */
+#define MACHO_HEADER_SIZE	(28)
+#define MACHO_SEGCMD_SIZE	(56)
+#define MACHO_SECTCMD_SIZE	(68)
+#define MACHO_SYMCMD_SIZE	(24)
+#define MACHO_NLIST_SIZE	(12)
+#define MACHO_RELINFO_SIZE	(8)
+
+/* Mach-O file header values */
+#define	MH_MAGIC		(0xfeedface)
+#define CPU_TYPE_I386		(7)     /* x86 platform */
+#define	CPU_SUBTYPE_I386_ALL	(3)     /* all-x86 compatible */
+#define	MH_OBJECT		(0x1)   /* object file */
+
+#define	LC_SEGMENT		(0x1)   /* segment load command */
+#define LC_SYMTAB		(0x2)   /* symbol table load command */
+
+#define	VM_PROT_NONE	(0x00)
+#define VM_PROT_READ	(0x01)
+#define VM_PROT_WRITE	(0x02)
+#define VM_PROT_EXECUTE	(0x04)
+
+#define VM_PROT_DEFAULT	(VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
+#define VM_PROT_ALL	(VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
+
+struct section {
+    /* nasm internal data */
+    struct section *next;
+    struct SAA *data;
+    long index;
+    struct reloc *relocs;
+    int align;
+
+    /* data that goes into the file */
+    char sectname[16];          /* what this section is called */
+    char segname[16];           /* segment this section will be in */
+    unsigned long size;         /* in-memory and -file size  */
+    unsigned long nreloc;       /* relocation entry count */
+    unsigned long flags;        /* type and attributes (masked) */
+};
+
+#define SECTION_TYPE	0x000000ff      /* section type mask */
+
+#define	S_REGULAR	(0x0)   /* standard section */
+#define	S_ZEROFILL	(0x1)   /* zerofill, in-memory only */
+
+#define SECTION_ATTRIBUTES_SYS   0x00ffff00     /* system setable attributes */
+#define S_ATTR_SOME_INSTRUCTIONS 0x00000400     /* section contains some
+                                                   machine instructions */
+#define S_ATTR_EXT_RELOC         0x00000200     /* section has external
+                                                   relocation entries */
+#define S_ATTR_LOC_RELOC         0x00000100     /* section has local
+                                                   relocation entries */
+
+
+static struct sectmap {
+    const char *nasmsect;
+    const char *segname;
+    const char *sectname;
+    const long flags;
+} sectmap[] = { {
+".text", "__TEXT", "__text", S_REGULAR|S_ATTR_SOME_INSTRUCTIONS}, {
+".data", "__DATA", "__data", S_REGULAR}, {
+".rodata", "__DATA", "__const", S_REGULAR}, {
+".bss", "__DATA", "__bss", S_ZEROFILL}, {
+NULL, NULL, NULL}};
+
+struct reloc {
+    /* nasm internal data */
+    struct reloc *next;
+
+    /* data that goes into the file */
+    long addr;                  /* op's offset in section */
+    unsigned int snum:24,       /* contains symbol index if
+				** ext otherwise in-file
+				** section number */
+	pcrel:1,                /* relative relocation */
+	length:2,               /* 0=byte, 1=word, 2=long */
+	ext:1,                  /* external symbol referenced */
+	type:4;                 /* reloc type, 0 for us */
+};
+
+#define	R_ABS		0       /* absolute relocation */
+#define R_SCATTERED	0x80000000      /* reloc entry is scattered if
+					** highest bit == 1 */
+
+struct symbol {
+    /* nasm internal data */
+    struct symbol *next;	/* next symbol in the list */
+    char *name;			/* name of this symbol */
+    long initial_snum;	       	/* symbol number used above in
+				   reloc */
+    long snum;			/* true snum for reloc */
+
+    /* data that goes into the file */
+    long strx;                  /* string table index */
+    unsigned char type;         /* symbol type */
+    unsigned char sect;         /* NO_SECT or section number */
+    short desc;                 /* for stab debugging, 0 for us */
+    unsigned long value;        /* offset of symbol in section */
+};
+
+/* symbol type bits */
+#define	N_EXT	0x01            /* global or external symbol */
+
+#define	N_UNDF	0x0             /* undefined symbol | n_sect == */
+#define	N_ABS	0x2             /* absolute symbol  |  NO_SECT */
+#define	N_SECT	0xe             /* defined symbol, n_sect holds
+				** section number */
+
+#define	N_TYPE	0x0e            /* type bit mask */
+
+#define DEFAULT_SECTION_ALIGNMENT 0 /* byte (i.e. no) alignment */
+
+/* special section number values */
+#define	NO_SECT		0       /* no section, invalid */
+#define MAX_SECT	255     /* maximum number of sections */
+
+static struct section *sects, **sectstail;
+static struct symbol *syms, **symstail;
+static unsigned long nsyms;
+
+/* These variables are set by macho_layout_symbols() to organize
+   the symbol table and string table in order the dynamic linker
+   expects.  They are then used in macho_write() to put out the
+   symbols and strings in that order.
+
+   The order of the symbol table is:
+     local symbols
+     defined external symbols (sorted by name)
+     undefined external symbols (sorted by name)
+
+   The order of the string table is:
+     strings for external symbols
+     strings for local symbols
+ */
+static unsigned long ilocalsym = 0;
+static unsigned long iextdefsym = 0;
+static unsigned long iundefsym = 0;
+static unsigned long nlocalsym;
+static unsigned long nextdefsym;
+static unsigned long nundefsym;
+static struct symbol **extdefsyms = NULL;
+static struct symbol **undefsyms = NULL;
+
+static struct RAA *extsyms;
+static struct SAA *strs;
+static unsigned long strslen;
+
+static FILE *machofp;
+static efunc error;
+static evalfunc evaluate;
+
+extern struct ofmt of_macho;
+
+/* Global file information. This should be cleaned up into either
+   a structure or as function arguments.  */
+unsigned long head_ncmds = 0;
+unsigned long head_sizeofcmds = 0;
+unsigned long seg_filesize = 0;
+unsigned long seg_vmsize = 0;
+unsigned long seg_nsects = 0;
+unsigned long rel_padcnt = 0;
+
+
+#define xstrncpy(xdst, xsrc)						\
+    memset(xdst, '\0', sizeof(xdst));	/* zero out whole buffer */	\
+    strncpy(xdst, xsrc, sizeof(xdst));	/* copy over string */		\
+    xdst[sizeof(xdst) - 1] = '\0';      /* proper null-termination */
+
+#define align(x, y)							\
+    (((x) + (y) - 1) & ~((y) - 1))      /* align x to multiple of y */
+
+#define alignlong(x)							\
+    align(x, sizeof(long))      /* align x to long boundary */
+
+static void debug_reloc (struct reloc *);
+static void debug_section_relocs (struct section *) __attribute__ ((unused));
+
+static int exact_log2 (unsigned long align) {
+    if (align != (align & -align)) {
+	return -1;
+    } else {
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GCC_MINOR__ >= 4)
+	return (align ? __builtin_ctzl (align) : 0);
+#else
+	unsigned long result = 0;
+
+	while (align >>= 1) {
+	    ++result;
+	}
+
+	return result;
+#endif
+    }
+}
+
+static struct section *get_section_by_name(const char *segname,
+                                           const char *sectname)
+{
+    struct section *s;
+
+    for (s = sects; s != NULL; s = s->next)
+        if (!strcmp(s->segname, segname) && !strcmp(s->sectname, sectname))
+            break;
+
+    return s;
+}
+
+static struct section *get_section_by_index(const long index)
+{
+    struct section *s;
+
+    for (s = sects; s != NULL; s = s->next)
+        if (index == s->index)
+            break;
+
+    return s;
+}
+
+static long get_section_index_by_name(const char *segname,
+                                      const char *sectname)
+{
+    struct section *s;
+
+    for (s = sects; s != NULL; s = s->next)
+        if (!strcmp(s->segname, segname) && !strcmp(s->sectname, sectname))
+            return s->index;
+
+    return -1;
+}
+
+static char *get_section_name_by_index(const long index)
+{
+    struct section *s;
+
+    for (s = sects; s != NULL; s = s->next)
+        if (index == s->index)
+            return s->sectname;
+
+    return NULL;
+}
+
+static unsigned char get_section_fileindex_by_index(const long index)
+{
+    struct section *s;
+    unsigned char i = 1;
+
+    for (s = sects; s != NULL && i < MAX_SECT; s = s->next, ++i)
+        if (index == s->index)
+            return i;
+
+    if (i == MAX_SECT)
+        error(ERR_WARNING,
+              "too many sections (>255) - clipped by fileindex");
+
+    return NO_SECT;
+}
+
+static void macho_init(FILE * fp, efunc errfunc, ldfunc ldef,
+                       evalfunc eval)
+{
+    char zero = 0;
+
+    machofp = fp;
+    error = errfunc;
+    evaluate = eval;
+
+    (void)ldef;                 /* placate optimisers */
+
+    sects = NULL;
+    sectstail = &sects;
+
+    syms = NULL;
+    symstail = &syms;
+    nsyms = 0;
+    nlocalsym = 0;
+    nextdefsym = 0;
+    nundefsym = 0;
+
+    extsyms = raa_init();
+    strs = saa_init(1L);
+
+    /* string table starts with a zero byte - don't ask why */
+    saa_wbytes(strs, &zero, sizeof(char));
+    strslen = 1;
+}
+
+static int macho_setinfo(enum geninfo type, char **val)
+{
+    return 0;
+}
+
+static void sect_write(struct section *sect,
+                       const unsigned char *data, unsigned long len)
+{
+    saa_wbytes(sect->data, data, len);
+    sect->size += len;
+}
+
+static void add_reloc(struct section *sect, long section,
+                      int pcrel, int bytes)
+{
+    struct reloc *r;
+    long fi;
+
+    /* NeXT as puts relocs in reversed order (address-wise) into the
+     ** files, so we do the same, doesn't seem to make much of a
+     ** difference either way */
+    r = nasm_malloc(sizeof(struct reloc));
+    r->next = sect->relocs;
+    sect->relocs = r;
+
+    /* the current end of the section will be the symbol's address for
+     ** now, might have to be fixed by macho_fixup_relocs() later on. make
+     ** sure we don't make the symbol scattered by setting the highest
+     ** bit by accident */
+    r->addr = sect->size & ~R_SCATTERED;
+    r->ext = 0;
+    r->pcrel = pcrel;
+
+    /* match byte count 1, 2, 4 to length codes 0, 1, 2 respectively */
+    r->length = bytes >> 1;
+
+    /* vanilla relocation (GENERIC_RELOC_VANILLA) */
+    r->type = 0;
+
+    if (section == NO_SEG) {
+        /* absolute local symbol if no section index given */
+        r->snum = R_ABS;
+    } else {
+        fi = get_section_fileindex_by_index(section);
+
+        if (fi == NO_SECT) {
+            /* external symbol if no section with that index known,
+             ** symbol number was saved in macho_symdef() */
+            r->snum = raa_read(extsyms, section);
+            r->ext = 1;
+        } else {
+            /* local symbol in section fi */
+            r->snum = fi;
+        }
+    }
+
+    ++sect->nreloc;
+}
+
+static void macho_output(long secto, const void *data, unsigned long type,
+                         long section, long wrt)
+{
+    struct section *s, *sbss;
+    long realbytes = type & OUT_SIZMASK;
+    long addr;
+    unsigned char mydata[4], *p;
+
+    type &= OUT_TYPMASK;
+
+    if (wrt != NO_SEG) {
+        wrt = NO_SEG;
+        error(ERR_NONFATAL, "WRT not supported by Mach-O output format");
+        /* continue to do _something_ */
+    }
+
+    if (secto == NO_SEG) {
+        if (type != OUT_RESERVE)
+            error(ERR_NONFATAL, "attempt to assemble code in "
+                  "[ABSOLUTE] space");
+
+        return;
+    }
+
+    s = get_section_by_index(secto);
+
+    if (s == NULL) {
+        error(ERR_WARNING, "attempt to assemble code in"
+              " section %d: defaulting to `.text'", secto);
+        s = get_section_by_name("__TEXT", "__text");
+
+        /* should never happen */
+        if (s == NULL)
+            error(ERR_PANIC, "text section not found");
+    }
+
+    sbss = get_section_by_name("__DATA", "__bss");
+
+    if (s == sbss && type != OUT_RESERVE) {
+        error(ERR_WARNING, "attempt to initialise memory in the"
+              " BSS section: ignored");
+
+        switch (type) {
+        case OUT_REL2ADR:
+            realbytes = 2;
+            break;
+
+        case OUT_REL4ADR:
+            realbytes = 4;
+            break;
+
+        default:
+            break;
+        }
+
+        s->size += realbytes;
+        return;
+    }
+
+    switch (type) {
+    case OUT_RESERVE:
+        if (s != sbss) {
+            error(ERR_WARNING, "uninitialised space declared in"
+                  " %s section: zeroing",
+                  get_section_name_by_index(secto));
+
+            sect_write(s, NULL, realbytes);
+        } else
+            s->size += realbytes;
+
+        break;
+
+    case OUT_RAWDATA:
+        if (section != NO_SEG)
+            error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
+
+        sect_write(s, data, realbytes);
+        break;
+
+    case OUT_ADDRESS:
+        addr = *(long *)data;
+
+        if (section != NO_SEG) {
+            if (section % 2) {
+                error(ERR_NONFATAL, "Mach-O format does not support"
+                      " section base references");
+            } else
+                add_reloc(s, section, 0, realbytes);
+        }
+
+        p = mydata;
+
+        if (realbytes == 2)
+            WRITESHORT(p, addr);
+        else
+            WRITELONG(p, addr);
+
+        sect_write(s, mydata, realbytes);
+        break;
+
+    case OUT_REL2ADR:
+        if (section == secto)
+            error(ERR_PANIC, "intra-section OUT_REL2ADR");
+
+        if (section != NO_SEG && section % 2) {
+            error(ERR_NONFATAL, "Mach-O format does not support"
+                  " section base references");
+        } else
+            add_reloc(s, section, 1, 2);
+
+        p = mydata;
+        WRITESHORT(p, *(long *)data - (realbytes + s->size));
+        sect_write(s, mydata, 2L);
+        break;
+
+    case OUT_REL4ADR:
+        if (section == secto)
+            error(ERR_PANIC, "intra-section OUT_REL4ADR");
+
+        if (section != NO_SEG && section % 2) {
+            error(ERR_NONFATAL, "Mach-O format does not support"
+                  " section base references");
+        } else
+            add_reloc(s, section, 1, 4);
+
+        p = mydata;
+        WRITELONG(p, *(long *)data - (realbytes + s->size));
+        sect_write(s, mydata, 4L);
+        break;
+
+    default:
+        error(ERR_PANIC, "unknown output type?");
+        break;
+    }
+}
+
+static long macho_section(char *name, int pass, int *bits)
+{
+    long index, originalIndex;
+    char *sectionAttributes;
+    struct sectmap *sm;
+    struct section *s;
+
+    /* Default to 32 bits. */
+    if (!name) {
+        *bits = 32;
+        name = ".text";
+        sectionAttributes = NULL;
+    } else {
+        sectionAttributes = name;
+        name = strsep(&sectionAttributes, " \t");
+    }
+
+    for (sm = sectmap; sm->nasmsect != NULL; ++sm) {
+        /* make lookup into section name translation table */
+        if (!strcmp(name, sm->nasmsect)) {
+            char *currentAttribute;
+
+            /* try to find section with that name */
+            originalIndex = index = get_section_index_by_name(sm->segname,
+                                                              sm->sectname);
+
+            /* create it if it doesn't exist yet */
+            if (index == -1) {
+                s = *sectstail = nasm_malloc(sizeof(struct section));
+                s->next = NULL;
+                sectstail = &s->next;
+
+                s->data = saa_init(1L);
+                s->index = seg_alloc();
+                s->relocs = NULL;
+                s->align = DEFAULT_SECTION_ALIGNMENT;
+
+                xstrncpy(s->segname, sm->segname);
+                xstrncpy(s->sectname, sm->sectname);
+                s->size = 0;
+                s->nreloc = 0;
+                s->flags = sm->flags;
+
+                index = s->index;
+            } else {
+                s = get_section_by_index(index);
+            }
+
+            while ((NULL != sectionAttributes)
+                   && (currentAttribute = strsep(&sectionAttributes, " \t"))) {
+                if (0 != *currentAttribute) {
+                    if (0 == strncasecmp("align=", currentAttribute, 6)) {
+                        char *end;
+                        int newAlignment, value;
+
+                        value = strtoul(currentAttribute + 6, &end, 0);
+                        newAlignment = exact_log2(value);
+
+                        if (0 != *end) {
+                            error(ERR_PANIC,
+                                  "unknown or missing alignment value \"%s\" "
+                                      "specified for section \"%s\"",
+                                  currentAttribute + 6,
+                                  name);
+                            return NO_SEG;
+                        } else if (0 > newAlignment) {
+                            error(ERR_PANIC,
+                                  "alignment of %d (for section \"%s\") is not "
+                                      "a power of two",
+                                  value,
+                                  name);
+                            return NO_SEG;
+                        }
+
+                        if ((-1 != originalIndex)
+                            && (s->align != newAlignment)) {
+                            error(ERR_PANIC,
+                                  "section \"%s\" has already been specified "
+                                      "with alignment %d, conflicts with new "
+                                      "alignment of %d",
+                            name,
+                            (1 << s->align),
+                            value);
+                            return NO_SEG;
+                        }
+
+                        s->align = newAlignment;
+                    } else if (0 == strcasecmp("data", currentAttribute)) {
+                        /* Do nothing; 'data' is implicit */
+                    } else {
+                        error(ERR_PANIC,
+                              "unknown section attribute %s for section %s",
+                              currentAttribute,
+                              name);
+                        return NO_SEG;
+                    }
+                }
+            }
+
+            return index;
+        }
+    }
+
+    error(ERR_PANIC, "invalid section name %s", name);
+    return NO_SEG;
+}
+
+static void macho_symdef(char *name, long section, long offset,
+                         int is_global, char *special)
+{
+    struct symbol *sym;
+
+    if (special) {
+        error(ERR_NONFATAL, "The Mach-O output format does "
+              "not support any special symbol types");
+        return;
+    }
+
+    if (is_global == 3) {
+        error(ERR_NONFATAL, "The Mach-O format does not "
+              "(yet) support forward reference fixups.");
+        return;
+    }
+
+    sym = *symstail = nasm_malloc(sizeof(struct symbol));
+    sym->next = NULL;
+    symstail = &sym->next;
+
+    sym->name = name;
+    sym->strx = strslen;
+    sym->type = 0;
+    sym->desc = 0;
+    sym->value = offset;
+    sym->initial_snum = -1;
+
+    /* external and common symbols get N_EXT */
+    if (is_global != 0)
+        sym->type |= N_EXT;
+
+    if (section == NO_SEG) {
+        /* symbols in no section get absolute */
+        sym->type |= N_ABS;
+        sym->sect = NO_SECT;
+    } else {
+        sym->type |= N_SECT;
+
+        /* get the in-file index of the section the symbol was defined in */
+        sym->sect = get_section_fileindex_by_index(section);
+
+        if (sym->sect == NO_SECT) {
+            /* remember symbol number of references to external
+             ** symbols, this works because every external symbol gets
+             ** its own section number allocated internally by nasm and
+             ** can so be used as a key */
+	    extsyms = raa_write(extsyms, section, nsyms);
+	    sym->initial_snum = nsyms;
+
+            switch (is_global) {
+            case 1:
+            case 2:
+                /* there isn't actually a difference between global
+                 ** and common symbols, both even have their size in
+                 ** sym->value */
+                sym->type = N_EXT;
+                break;
+
+            default:
+                /* give an error on unfound section if it's not an
+                 ** external or common symbol (assemble_file() does a
+                 ** seg_alloc() on every call for them) */
+                error(ERR_PANIC, "in-file index for section %d not found",
+                      section);
+            }
+        }
+    }
+
+    ++nsyms;
+}
+
+static long macho_segbase(long section)
+{
+    return section;
+}
+
+static int macho_directive(char *directive, char *value, int pass)
+{
+    return 0;
+}
+
+static void macho_filename(char *inname, char *outname, efunc error)
+{
+    standard_extension(inname, outname, ".o", error);
+}
+
+static const char *macho_stdmac[] = {
+    "%define __SECT__ [section .text]",
+    "%macro __NASM_CDecl__ 1",
+    "%endmacro",
+    NULL
+};
+
+/* Comparison function for qsort symbol layout.  */
+static int layout_compare (const struct symbol **s1,
+			   const struct symbol **s2)
+{
+    return (strcmp ((*s1)->name, (*s2)->name));
+}
+
+/* The native assembler does a few things in a similar function
+
+	* Remove temporary labels
+	* Sort symbols according to local, external, undefined (by name)
+	* Order the string table
+
+   We do not remove temporary labels right now.
+
+   numsyms is the total number of symbols we have. strtabsize is the
+   number entries in the string table.  */
+
+static void macho_layout_symbols (unsigned long *numsyms,
+				  unsigned long *strtabsize)
+{
+    struct symbol *sym, **symp;
+    unsigned long i,j;
+
+    *numsyms = 0;
+    *strtabsize = sizeof (char);
+
+    symp = &syms;
+
+    while ((sym = *symp)) {
+	/* Undefined symbols are now external.  */
+	if (sym->type == N_UNDF)
+	    sym->type |= N_EXT;
+
+	if ((sym->type & N_EXT) == 0) {
+	    sym->snum = *numsyms;
+	    *numsyms = *numsyms + 1;
+	    nlocalsym++;
+	}
+	else {
+	    if ((sym->type & N_TYPE) != N_UNDF)
+		nextdefsym++;
+	    else
+		nundefsym++;
+
+	    /* If we handle debug info we'll want
+	       to check for it here instead of just
+	       adding the symbol to the string table.  */
+	    sym->strx = *strtabsize;
+	    saa_wbytes (strs, sym->name, (long)(strlen(sym->name) + 1));
+	    *strtabsize += strlen(sym->name) + 1;
+	}
+	symp = &(sym->next);
+    }
+
+    /* Next, sort the symbols.  Most of this code is a direct translation from
+       the Apple cctools symbol layout. We need to keep compatibility with that.  */
+    /* Set the indexes for symbol groups into the symbol table */
+    ilocalsym = 0;
+    iextdefsym = nlocalsym;
+    iundefsym = nlocalsym + nextdefsym;
+
+    /* allocate arrays for sorting externals by name */
+    extdefsyms = nasm_malloc(nextdefsym * sizeof(struct symbol *));
+    undefsyms = nasm_malloc(nundefsym * sizeof(struct symbol *));
+
+    i = 0;
+    j = 0;
+
+    symp = &syms;
+
+    while ((sym = *symp)) {
+
+	if((sym->type & N_EXT) == 0) {
+	    sym->strx = *strtabsize;
+	    saa_wbytes (strs, sym->name, (long)(strlen (sym->name) + 1));
+	    *strtabsize += strlen(sym->name) + 1;
+	}
+	else {
+	    if((sym->type & N_TYPE) != N_UNDF)
+		extdefsyms[i++] = sym;
+	    else
+		undefsyms[j++] = sym;
+	}
+	symp = &(sym->next);
+    }
+
+    qsort(extdefsyms, nextdefsym, sizeof(struct symbol *),
+	  (int (*)(const void *, const void *))layout_compare);
+    qsort(undefsyms, nundefsym, sizeof(struct symbol *),
+	  (int (*)(const void *, const void *))layout_compare);
+
+    for(i = 0; i < nextdefsym; i++) {
+	extdefsyms[i]->snum = *numsyms;
+	*numsyms += 1;
+    }
+    for(j = 0; j < nundefsym; j++) {
+	undefsyms[j]->snum = *numsyms;
+	*numsyms += 1;
+    }
+}
+
+/* Calculate some values we'll need for writing later.  */
+
+static void macho_calculate_sizes (void)
+{
+    struct section *s;
+
+    /* count sections and calculate in-memory and in-file offsets */
+    for (s = sects; s != NULL; s = s->next) {
+        /* zerofill sections aren't actually written to the file */
+        if ((s->flags & SECTION_TYPE) != S_ZEROFILL)
+            seg_filesize += s->size;
+
+        seg_vmsize += s->size;
+        ++seg_nsects;
+    }
+
+    /* calculate size of all headers, load commands and sections to
+    ** get a pointer to the start of all the raw data */
+    if (seg_nsects > 0) {
+        ++head_ncmds;
+        head_sizeofcmds +=
+            MACHO_SEGCMD_SIZE + seg_nsects * MACHO_SECTCMD_SIZE;
+    }
+
+    if (nsyms > 0) {
+	++head_ncmds;
+	head_sizeofcmds += MACHO_SYMCMD_SIZE;
+    }
+}
+
+/* Write out the header information for the file.  */
+
+static void macho_write_header (void)
+{
+    fwritelong(MH_MAGIC, machofp);	/* magic */
+    fwritelong(CPU_TYPE_I386, machofp);	/* CPU type */
+    fwritelong(CPU_SUBTYPE_I386_ALL, machofp);	/* CPU subtype */
+    fwritelong(MH_OBJECT, machofp);	/* Mach-O file type */
+    fwritelong(head_ncmds, machofp);	/* number of load commands */
+    fwritelong(head_sizeofcmds, machofp);	/* size of load commands */
+    fwritelong(0, machofp);	/* no flags */
+}
+
+/* Write out the segment load command at offset.  */
+
+static unsigned long macho_write_segment (unsigned long offset)
+{
+    unsigned long s_addr = 0;
+    unsigned long rel_base = alignlong (offset + seg_filesize);
+    unsigned long s_reloff = 0;
+    struct section *s;
+
+    fwritelong(LC_SEGMENT, machofp);        /* cmd == LC_SEGMENT */
+
+    /* size of load command including section load commands */
+    fwritelong(MACHO_SEGCMD_SIZE + seg_nsects *
+	       MACHO_SECTCMD_SIZE, machofp);
+
+    /* in an MH_OBJECT file all sections are in one unnamed (name
+    ** all zeros) segment */
+    fwrite("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16, 1, machofp);
+    fwritelong(0, machofp); /* in-memory offset */
+    fwritelong(seg_vmsize, machofp);        /* in-memory size */
+    fwritelong(offset, machofp);    /* in-file offset to data */
+    fwritelong(seg_filesize, machofp);      /* in-file size */
+    fwritelong(VM_PROT_DEFAULT, machofp);   /* maximum vm protection */
+    fwritelong(VM_PROT_DEFAULT, machofp);   /* initial vm protection */
+    fwritelong(seg_nsects, machofp);        /* number of sections */
+    fwritelong(0, machofp); /* no flags */
+
+    /* emit section headers */
+    for (s = sects; s != NULL; s = s->next) {
+	fwrite(s->sectname, sizeof(s->sectname), 1, machofp);
+	fwrite(s->segname, sizeof(s->segname), 1, machofp);
+	fwritelong(s_addr, machofp);
+	fwritelong(s->size, machofp);
+
+	/* dummy data for zerofill sections or proper values */
+	if ((s->flags & SECTION_TYPE) != S_ZEROFILL) {
+	    fwritelong(offset, machofp);
+	    /* Write out section alignment, as a power of two.
+	       e.g. 32-bit word alignment would be 2 (2^^2 = 4).  */
+	    fwritelong(s->align, machofp);
+	    /* To be compatible with cctools as we emit
+	       a zero reloff if we have no relocations.  */
+	    fwritelong(s->nreloc ? rel_base + s_reloff : 0, machofp);
+	    fwritelong(s->nreloc, machofp);
+
+	    offset += s->size;
+	    s_reloff += s->nreloc * MACHO_RELINFO_SIZE;
+	} else {
+	    fwritelong(0, machofp);
+	    fwritelong(0, machofp);
+	    fwritelong(0, machofp);
+	    fwritelong(0, machofp);
+	}
+
+	fwritelong(s->flags, machofp);      /* flags */
+	fwritelong(0, machofp);     /* reserved */
+	fwritelong(0, machofp);     /* reserved */
+
+	s_addr += s->size;
+    }
+
+    rel_padcnt = rel_base - offset;
+    offset = rel_base + s_reloff;
+
+    return offset;
+}
+
+/* For a given chain of relocs r, write out the entire relocation
+   chain to the object file.  */
+
+static void macho_write_relocs (struct reloc *r)
+{
+    while (r) {
+	unsigned long word2;
+
+	fwritelong(r->addr, machofp); /* reloc offset */
+
+	word2 = r->snum;
+	word2 |= r->pcrel << 24;
+	word2 |= r->length << 25;
+	word2 |= r->ext << 27;
+	word2 |= r->type << 28;
+	fwritelong(word2, machofp); /* reloc data */
+
+	r = r->next;
+    }
+}
+
+/* Write out the section data.  */
+static void macho_write_section (void)
+{
+    struct section *s, *s2;
+    struct reloc *r;
+    char *rel_paddata = "\0\0\0";
+    unsigned char fi, *p, *q, blk[4];
+    long l;
+
+    for (s = sects; s != NULL; s = s->next) {
+	if ((s->flags & SECTION_TYPE) == S_ZEROFILL)
+	    continue;
+
+	/* no padding needs to be done to the sections */
+
+	/* Like a.out Mach-O references things in the data or bss
+	 * sections by addresses which are actually relative to the
+	 * start of the _text_ section, in the _file_. See outaout.c
+	 * for more information. */
+	saa_rewind(s->data);
+	for (r = s->relocs; r != NULL; r = r->next) {
+	    saa_fread(s->data, r->addr, blk, (long)r->length << 1);
+	    p = q = blk;
+	    l = *p++;
+
+	    /* get offset based on relocation type */
+	    if (r->length > 0) {
+		l += ((long)*p++) << 8;
+
+		if (r->length == 2) {
+		    l += ((long)*p++) << 16;
+		    l += ((long)*p++) << 24;
+		}
+	    }
+
+	    /* If the relocation is internal add to the current section
+	       offset. Otherwise the only value we need is the symbol
+	       offset which we already have. The linker takes care
+	       of the rest of the address.  */
+	    if (!r->ext) {
+		/* add sizes of previous sections to current offset */
+		for (s2 = sects, fi = 1;
+		     s2 != NULL && fi < r->snum; s2 = s2->next, fi++)
+		    if ((s2->flags & SECTION_TYPE) != S_ZEROFILL)
+			l += s2->size;
+	    }
+
+	    /* write new offset back */
+	    if (r->length == 2)
+		WRITELONG(q, l);
+	    else if (r->length == 1)
+		WRITESHORT(q, l);
+	    else
+		*q++ = l & 0xFF;
+
+	    saa_fwrite(s->data, r->addr, blk, (long)r->length << 1);
+	}
+
+	/* dump the section data to file */
+	saa_fpwrite(s->data, machofp);
+    }
+
+    /* pad last section up to reloc entries on long boundary */
+    fwrite(rel_paddata, rel_padcnt, 1, machofp);
+
+    /* emit relocation entries */
+    for (s = sects; s != NULL; s = s->next)
+	macho_write_relocs (s->relocs);
+}
+
+/* Write out the symbol table. We should already have sorted this
+   before now.  */
+static void macho_write_symtab (void)
+{
+    struct symbol *sym;
+    struct section *s;
+    long fi;
+    long i;
+
+    /* we don't need to pad here since MACHO_RELINFO_SIZE == 8 */
+
+    for (sym = syms; sym != NULL; sym = sym->next) {
+	if ((sym->type & N_EXT) == 0) {
+	    fwritelong(sym->strx, machofp);		/* string table entry number */
+	    fwrite(&sym->type, 1, 1, machofp);	/* symbol type */
+	    fwrite(&sym->sect, 1, 1, machofp);	/* section */
+	    fwriteshort(sym->desc, machofp);	/* description */
+
+	    /* Fix up the symbol value now that we know the final section
+	       sizes.  */
+	    if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) {
+		for (s = sects, fi = 1;
+		     s != NULL && fi < sym->sect; s = s->next, ++fi)
+		    sym->value += s->size;
+	    }
+
+	    fwritelong(sym->value, machofp);	/* value (i.e. offset) */
+	}
+    }
+
+    for (i = 0; i < nextdefsym; i++) {
+	sym = extdefsyms[i];
+	fwritelong(sym->strx, machofp);
+	fwrite(&sym->type, 1, 1, machofp);	/* symbol type */
+	fwrite(&sym->sect, 1, 1, machofp);	/* section */
+	fwriteshort(sym->desc, machofp);	/* description */
+
+	/* Fix up the symbol value now that we know the final section
+	   sizes.  */
+	if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) {
+	    for (s = sects, fi = 1;
+		 s != NULL && fi < sym->sect; s = s->next, ++fi)
+		sym->value += s->size;
+	}
+
+	fwritelong(sym->value, machofp);	/* value (i.e. offset) */
+    }
+
+     for (i = 0; i < nundefsym; i++) {
+	 sym = undefsyms[i];
+	 fwritelong(sym->strx, machofp);
+	 fwrite(&sym->type, 1, 1, machofp);	/* symbol type */
+	 fwrite(&sym->sect, 1, 1, machofp);	/* section */
+	 fwriteshort(sym->desc, machofp);	/* description */
+
+	 /* Fix up the symbol value now that we know the final section
+	    sizes.  */
+	 if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) {
+	     for (s = sects, fi = 1;
+		  s != NULL && fi < sym->sect; s = s->next, ++fi)
+		 sym->value += s->size;
+	 }
+
+	 fwritelong(sym->value, machofp);	/* value (i.e. offset) */
+     }
+}
+
+/* Fixup the snum in the relocation entries, we should be
+   doing this only for externally undefined symbols. */
+static void macho_fixup_relocs (struct reloc *r)
+{
+    struct symbol *sym;
+    int i;
+
+    while (r != NULL) {
+	if (r->ext) {
+	    for (i = 0; i < nundefsym; i++) {
+		sym = undefsyms[i];
+		if (sym->initial_snum == r->snum) {
+		    r->snum = sym->snum;
+		}
+	    }
+	}
+	r = r->next;
+    }
+}
+
+/* Write out the object file.  */
+
+static void macho_write (void)
+{
+    unsigned long offset = 0;
+
+    /* mach-o object file structure:
+    **
+    ** mach header
+    **  ulong magic
+    **  int   cpu type
+    **  int   cpu subtype
+    **  ulong mach file type
+    **  ulong number of load commands
+    **  ulong size of all load commands
+    **   (includes section struct size of segment command)
+    **  ulong flags
+    **
+    ** segment command
+    **  ulong command type == LC_SEGMENT
+    **  ulong size of load command
+    **   (including section load commands)
+    **  char[16] segment name
+    **  ulong in-memory offset
+    **  ulong in-memory size
+    **  ulong in-file offset to data area
+    **  ulong in-file size
+    **   (in-memory size excluding zerofill sections)
+    **  int   maximum vm protection
+    **  int   initial vm protection
+    **  ulong number of sections
+    **  ulong flags
+    **
+    ** section commands
+    **   char[16] section name
+    **   char[16] segment name
+    **   ulong in-memory offset
+    **   ulong in-memory size
+    **   ulong in-file offset
+    **   ulong alignment
+    **    (irrelevant in MH_OBJECT)
+    **   ulong in-file offset of relocation entires
+    **   ulong number of relocations
+    **   ulong flags
+    **   ulong reserved
+    **   ulong reserved
+    **
+    ** symbol table command
+    **  ulong command type == LC_SYMTAB
+    **  ulong size of load command
+    **  ulong symbol table offset
+    **  ulong number of symbol table entries
+    **  ulong string table offset
+    **  ulong string table size
+    **
+    ** raw section data
+    **
+    ** padding to long boundary
+    **
+    ** relocation data (struct reloc)
+    ** long offset
+    **  uint data (symbolnum, pcrel, length, extern, type)
+    **
+    ** symbol table data (struct nlist)
+    **  long  string table entry number
+    **  uchar type
+    **   (extern, absolute, defined in section)
+    **  uchar section
+    **   (0 for global symbols, section number of definition (>= 1, <=
+    **   254) for local symbols, size of variable for common symbols
+    **   [type == extern])
+    **  short description
+    **   (for stab debugging format)
+    **  ulong value (i.e. file offset) of symbol or stab offset
+    **
+    ** string table data
+    **  list of null-terminated strings
+    */
+
+    /* Emit the Mach-O header.  */
+    macho_write_header();
+
+    offset = MACHO_HEADER_SIZE + head_sizeofcmds;
+
+    /* emit the segment load command */
+    if (seg_nsects > 0)
+	offset = macho_write_segment (offset);
+    else
+        error(ERR_WARNING, "no sections?");
+
+    if (nsyms > 0) {
+        /* write out symbol command */
+        fwritelong(LC_SYMTAB, machofp); /* cmd == LC_SYMTAB */
+        fwritelong(MACHO_SYMCMD_SIZE, machofp); /* size of load command */
+        fwritelong(offset, machofp);    /* symbol table offset */
+        fwritelong(nsyms, machofp);     /* number of symbol
+                                         ** table entries */
+
+        offset += nsyms * MACHO_NLIST_SIZE;
+        fwritelong(offset, machofp);    /* string table offset */
+        fwritelong(strslen, machofp);   /* string table size */
+    }
+
+    /* emit section data */
+    if (seg_nsects > 0)
+	macho_write_section ();
+
+    /* emit symbol table if we have symbols */
+    if (nsyms > 0)
+	macho_write_symtab ();
+
+    /* we don't need to pad here since MACHO_NLIST_SIZE == 12 */
+
+    /* emit string table */
+    saa_fpwrite(strs, machofp);
+}
+/* We do quite a bit here, starting with finalizing all of the data
+   for the object file, writing, and then freeing all of the data from
+   the file.  */
+
+static void macho_cleanup(int debuginfo)
+{
+    struct section *s;
+    struct reloc *r;
+    struct symbol *sym;
+
+    (void)debuginfo;
+
+    /* Sort all symbols.  */
+    macho_layout_symbols (&nsyms, &strslen);
+
+    /* Fixup relocation entries */
+    for (s = sects; s != NULL; s = s->next) {
+	macho_fixup_relocs (s->relocs);
+    }
+
+    /* First calculate and finalize needed values.  */
+    macho_calculate_sizes();
+    macho_write();
+
+    /* done - yay! */
+    fclose(machofp);
+
+    /* free up everything */
+    while (sects->next) {
+        s = sects;
+        sects = sects->next;
+
+        saa_free(s->data);
+        while (s->relocs != NULL) {
+            r = s->relocs;
+            s->relocs = s->relocs->next;
+            nasm_free(r);
+        }
+
+        nasm_free(s);
+    }
+
+    saa_free(strs);
+    raa_free(extsyms);
+
+    if (syms) {
+	while (syms->next) {
+	    sym = syms;
+	    syms = syms->next;
+
+	    nasm_free (sym);
+	}
+    }
+}
+
+/* Debugging routines.  */
+static void debug_reloc (struct reloc *r)
+{
+    fprintf (stdout, "reloc:\n");
+    fprintf (stdout, "\taddr: %ld\n", r->addr);
+    fprintf (stdout, "\tsnum: %d\n", r->snum);
+    fprintf (stdout, "\tpcrel: %d\n", r->pcrel);
+    fprintf (stdout, "\tlength: %d\n", r->length);
+    fprintf (stdout, "\text: %d\n", r->ext);
+    fprintf (stdout, "\ttype: %d\n", r->type);
+}
+
+static void debug_section_relocs (struct section *s)
+{
+    struct reloc *r = s->relocs;
+
+    fprintf (stdout, "relocs for section %s:\n\n", s->sectname);
+
+    while (r != NULL) {
+	debug_reloc (r);
+	r = r->next;
+    }
+}
+
+struct ofmt of_macho = {
+    "NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X object files",
+    "macho",
+    NULL,
+    null_debug_arr,
+    &null_debug_form,
+    macho_stdmac,
+    macho_init,
+    macho_setinfo,
+    macho_output,
+    macho_symdef,
+    macho_section,
+    macho_segbase,
+    macho_directive,
+    macho_filename,
+    macho_cleanup
+};
+
+#endif
+
+/*
+ * Local Variables:
+ * mode:c
+ * c-basic-offset:4
+ * End:
+ *
+ * end of file */
