diff options
author | Eric Christopher <echristo@apple.com> | 2005-09-22 21:22:33 +0000 |
---|---|---|
committer | Eric Christopher <echristo@apple.com> | 2005-09-22 21:22:33 +0000 |
commit | 1b8a72ae7ca58371cd1aef384609e80e32276cc3 (patch) | |
tree | 102e37a706ee5c45834a1a481bfe8aedf3b85b8b | |
parent | f3071da71e0ef3193d35a5afd1cc0c9cc4db5687 (diff) | |
download | nasm-1b8a72ae7ca58371cd1aef384609e80e32276cc3.tar.gz |
Add basic support for Mach-O file format.
-rw-r--r-- | Makefile.in | 2 | ||||
-rw-r--r-- | outform.h | 15 | ||||
-rw-r--r-- | output/outmacho.c | 925 |
3 files changed, 940 insertions, 2 deletions
diff --git a/Makefile.in b/Makefile.in index 445dfe6a..7d242af6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -51,7 +51,7 @@ NASM = nasm.$(O) nasmlib.$(O) float.$(O) insnsa.$(O) assemble.$(O) \ labels.$(O) parser.$(O) outform.$(O) output/outbin.$(O) \ output/outaout.$(O) output/outcoff.$(O) output/outelf.$(O) \ output/outobj.$(O) output/outas86.$(O) output/outrdf2.$(O) \ - output/outdbg.$(O) output/outieee.$(O) \ + output/outdbg.$(O) output/outieee.$(O) output/outmacho.$(O) \ preproc.$(O) listing.$(O) eval.$(O) NDISASM = ndisasm.$(O) disasm.$(O) sync.$(O) nasmlib.$(O) insnsd.$(O) @@ -57,7 +57,7 @@ /* ====configurable info begins here==== */ /* formats configurable: - * bin,obj,elf,aout,aoutb,coff,win32,as86,rdf2 */ + * bin,obj,elf,aout,aoutb,coff,win32,as86,rdf2,macho */ /* process options... */ @@ -98,6 +98,9 @@ #ifndef OF_IEEE #define OF_IEEE #endif +#ifndef OF_MACHO +#define OF_MACHO +#endif #endif /* OF_ALL */ /* turn on groups of formats specified.... */ @@ -141,6 +144,9 @@ #ifndef OF_IEEE #define OF_IEEE #endif +#ifndef OF_MACHO +#define OF_MACHO +#endif #endif /* finally... override any format specifically specified to be off */ @@ -174,6 +180,9 @@ #ifdef OF_NO_IEEE #undef OF_IEEE #endif +#ifdef OF_NO_MACHO +#undef OF_MACHO +#endif #ifndef OF_DEFAULT #define OF_DEFAULT of_bin @@ -194,6 +203,7 @@ extern struct ofmt of_obj; extern struct ofmt of_win32; extern struct ofmt of_rdf2; extern struct ofmt of_ieee; +extern struct ofmt of_macho; extern struct ofmt of_dbg; struct ofmt *drivers[] = { @@ -227,6 +237,9 @@ struct ofmt *drivers[] = { #ifdef OF_IEEE &of_ieee, #endif +#ifdef OF_MACHO + &of_macho, +#endif #ifdef OF_DBG &of_dbg, #endif diff --git a/output/outmacho.c b/output/outmacho.c new file mode 100644 index 00000000..2821aa0d --- /dev/null +++ b/output/outmacho.c @@ -0,0 +1,925 @@ +/* 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; + + /* 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 */ + +static struct sectmap { + const char *nasmsect; + const char *segname; + const char *sectname; + const long flags; +} sectmap[] = {{".text", "__TEXT", "__text", S_REGULAR}, + {".data", "__DATA", "__data", 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 { + 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 */ + +/* 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 SAA *syms; +static unsigned long nsyms; +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; + +#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 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 = §s; + + syms = saa_init((long)sizeof(struct symbol)); + nsyms = 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 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; + struct sectmap *sm; + struct section *s; + + /* Default to 32 bits. */ + if (!name) + *bits = 32; + + if (!name) + name = ".text"; + + for (sm = sectmap; sm->nasmsect != NULL; ++sm) { + /* make lookup into section name translation table */ + if (!strcmp(name, sm->nasmsect)) { + /* try to find section with that name */ + 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; + + xstrncpy(s->segname, sm->segname); + xstrncpy(s->sectname, sm->sectname); + s->size = 0; + s->nreloc = 0; + s->flags = sm->flags; + + index = s->index; + } + + 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 = saa_wstruct(syms); + + sym->strx = strslen; + sym->type = 0; + sym->desc = 0; + sym->value = offset; + + /* 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); + + 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); + } + } + } + + /* append symbol name to string table */ + saa_wbytes(strs, name, (long)(strlen(name) + 1)); + strslen += strlen(name) + 1; + + ++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 +}; + +static void macho_cleanup(int debuginfo) +{ + struct section *s; + struct reloc *r; + unsigned long offset, rel_padcnt = 0; + unsigned long head_ncmds = 0; + unsigned long head_sizeofcmds = 0; + unsigned long seg_nsects = 0; + unsigned long seg_filesize = 0; + unsigned long seg_vmsize = 0; + + (void) debuginfo; + + /* 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 + */ + + /* simplifications over native NeXTstep assembler: + ** - no support for dynamic linking/symbols/libraries, section differences + ** - no sorting of symbols and string table, normally its ordered like + ** - local symbols, defined external symbols, undefined external symbols + ** - strings for external symbols, strings for local symbols + ** we just dump them in the order given by the source file and nasm what + ** seems to work fine with the link editor + */ + + /* first calculate and finalise all needed values */ + + /* 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; + } + + /* emit the Mach-O header. */ + 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 */ + + offset = MACHO_HEADER_SIZE + head_sizeofcmds; + + /* emit the segment load command */ + if (seg_nsects > 0) { + unsigned long s_addr = 0; + unsigned long rel_base = alignlong(offset + seg_filesize); + unsigned long s_reloff = 0; + + 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); + fwritelong(0, 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; + } + + /* at this point offset has reached rel_base - alignment, + ** remember how much we'll have to pad and skip relocation + ** data */ + rel_padcnt = rel_base - offset; + offset = rel_base + s_reloff; + } 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) { + struct section *s2; + 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; + } + } + + /* 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) { + for (r = s->relocs; r != NULL; r = r->next) { + 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 */ + } + } + } + + /* emit symbol table */ + if (nsyms > 0) { + struct symbol *sym; + long fi, i; + + /* we don't need to pad here since MACHO_RELINFO_SIZE == 8 */ + + saa_rewind(syms); + for (i = 0; i < nsyms; ++i) { + sym = saa_rstruct(syms); + + 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 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) */ + } + } + + /* we don't need to pad here since MACHO_NLIST_SIZE == 12 */ + + /* emit string table */ + saa_fpwrite(strs, machofp); + + /* 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); + saa_free(syms); +} + +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 */ |