1/*
2 * Mac OS X ABI Mach-O File Format
3 *
4 *  Copyright (C) 2007 Henryk Richter, built upon xdf objfmt (C) Peter Johnson
5 *
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28/*
29  notes: This implementation is rather basic. There are several implementation
30         issues to be sorted out for full compliance and error resilience.
31         Some examples are given below (nasm syntax).
32
33  1) section placement
34     Mach-O requires BSS sections to be placed last in object files. This
35     has to be done manually.
36     Example:
37
38      section .text
39       mov rax,[qword foo]
40      section .data
41       dw  0
42      section .bss
43      foo dw 0
44
45  2) addressing issues
46
47  2.1) symbol relative relocation (i.e. mov eax,[foo wrt bar])
48       Not implemented yet.
49
50  2.2) data referencing in 64 bit mode
51       While ELF allows 32 bit absolute relocations in 64 bit mode, Mach-O
52       does not. Therefore code like
53        lea rbx,[_foo]  ;48 8d 1c 25 00 00 00 00
54        mov rcx,[_bar]  ;48 8b 0c 25 00 00 00 00
55       with a 32 bit address field cannot be relocated into an address >= 0x100000000 (OSX actually
56       uses that).
57
58       Actually, the only register where a 64 bit displacement is allowed in x86-64, is rax
59       as in the example 1).
60
61       A plausible workaround is either classic PIC (like in C), which is in turn
62       not implemented in this object format. The recommended was is PC relative
63       code (called RIP-relative in x86-64). So instead of the lines above, just write:
64        lea rbx,[_foo wrt rip]
65        mov rcx,[_bar wrt rip]
66
67  2.3) section/data alignment
68       Normally, you specify sections with a specific alignment
69       and get your data layed out as desired. Unfortunately, the
70       linker in MacOS X seems to ignore the section alignment requests.
71       The workaround is an explicit alignment at the end of the text section.
72
73       section .text
74        movdqa xmm0,[_foo wrt rip]
75
76        align 16
77       section .data align=16
78        _foo dw 32,32,32,32,32,32,32,32
79
80       FIXME: perform that operation implicitly!
81
82  2.4) cross section symbol differences unsupported in current implementation
83       [extern foo]
84       [extern bar]
85       section .data
86        dq bar-foo
87
88       Will currently produce an error though the necessary means are provided
89       by the Mach-O specification.
90
91*/
92
93#include <util.h>
94
95#include <libyasm.h>
96
97/* MACH-O DEFINES */
98/* Mach-O in-file header structure sizes (32 BIT, see below for 64 bit defs) */
99#define MACHO_HEADER_SIZE       28
100#define MACHO_SEGCMD_SIZE       56
101#define MACHO_SECTCMD_SIZE      68
102#define MACHO_SYMCMD_SIZE       24
103#define MACHO_NLIST_SIZE        12
104#define MACHO_RELINFO_SIZE      8
105
106/* 64 bit sizes */
107#define MACHO_HEADER64_SIZE     32
108#define MACHO_SEGCMD64_SIZE     72
109#define MACHO_SECTCMD64_SIZE    80
110#define MACHO_NLIST64_SIZE      16
111#define MACHO_RELINFO64_SIZE    8
112
113
114/* Mach-O file header values */
115#define MH_MAGIC                0xfeedface
116#define MH_MAGIC_64             0xfeedfacf
117
118/* CPU machine type */
119#define CPU_TYPE_I386           7       /* x86 platform */
120#define CPU_TYPE_X86_64         (CPU_TYPE_I386|CPU_ARCH_ABI64)
121#define CPU_ARCH_ABI64          0x01000000      /* 64 bit ABI */
122
123/* CPU machine subtype, e.g. processor */
124#define CPU_SUBTYPE_I386_ALL    3       /* all-x86 compatible */
125#define CPU_SUBTYPE_X86_64_ALL  CPU_SUBTYPE_I386_ALL
126#define CPU_SUBTYPE_386         3
127#define CPU_SUBTYPE_486         4
128#define CPU_SUBTYPE_486SX       (4 + 128)
129#define CPU_SUBTYPE_586         5
130#define CPU_SUBTYPE_INTEL(f, m) ((f) + ((m) << 4))
131#define CPU_SUBTYPE_PENT        CPU_SUBTYPE_INTEL(5, 0)
132#define CPU_SUBTYPE_PENTPRO     CPU_SUBTYPE_INTEL(6, 1)
133#define CPU_SUBTYPE_PENTII_M3   CPU_SUBTYPE_INTEL(6, 3)
134#define CPU_SUBTYPE_PENTII_M5   CPU_SUBTYPE_INTEL(6, 5)
135#define CPU_SUBTYPE_PENTIUM_4   CPU_SUBTYPE_INTEL(10, 0)
136
137#define CPU_SUBTYPE_INTEL_FAMILY(x)     ((x) & 15)
138#define CPU_SUBTYPE_INTEL_FAMILY_MAX    15
139
140#define CPU_SUBTYPE_INTEL_MODEL(x)      ((x) >> 4)
141#define CPU_SUBTYPE_INTEL_MODEL_ALL     0
142
143#define MH_OBJECT               0x1     /* object file */
144
145#define LC_SEGMENT              0x1     /* segment load command */
146#define LC_SYMTAB               0x2     /* symbol table load command */
147#define LC_SEGMENT_64           0x19    /* segment load command */
148
149
150#define VM_PROT_NONE            0x00
151#define VM_PROT_READ            0x01
152#define VM_PROT_WRITE           0x02
153#define VM_PROT_EXECUTE         0x04
154
155#define VM_PROT_DEFAULT (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
156#define VM_PROT_ALL     (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
157
158#define SECTION_TYPE        0x000000ff  /* section type mask */
159#define SECTION_ATTRIBUTES  0xffffff00UL/* section attributes mask */
160
161#define S_REGULAR           0x0         /* standard section */
162#define S_ZEROFILL          0x1         /* zerofill, in-memory only */
163#define S_CSTRING_LITERALS  0x2         /* literal C strings */
164#define S_4BYTE_LITERALS    0x3         /* only 4-byte literals */
165#define S_8BYTE_LITERALS    0x4         /* only 8-byte literals */
166#define S_LITERAL_POINTERS  0x5         /* only pointers to literals */
167#define S_NON_LAZY_SYMBOL_POINTERS  0x6 /* only non-lazy symbol pointers */
168#define S_LAZY_SYMBOL_POINTERS      0x7 /* only lazy symbol pointers */
169#define S_SYMBOL_STUBS      0x8         /* only symbol stubs; byte size of
170                                         * stub in the reserved2 field */
171#define S_MOD_INIT_FUNC_POINTERS    0x9 /* only function pointers for init */
172#define S_MOD_TERM_FUNC_POINTERS    0xa /* only function pointers for term */
173#define S_COALESCED         0xb         /* symbols that are to be coalesced */
174#define S_GB_ZEROFILL       0xc         /* >4GB zero fill on demand section */
175#define S_INTERPOSING       0xd         /* only pairs of function pointers for
176                                         * interposing */
177#define S_16BYTE_LITERALS   0xe         /* only 16 byte literals */
178
179#define S_ATTR_DEBUG             0x02000000     /* a debug section */
180#define SECTION_ATTRIBUTES_SYS   0x00ffff00     /* system setable attributes */
181#define S_ATTR_SOME_INSTRUCTIONS 0x00000400     /* section contains some
182                                                 * machine instructions */
183#define S_ATTR_EXT_RELOC         0x00000200     /* section has external
184                                                 * relocation entries */
185#define S_ATTR_LOC_RELOC         0x00000100     /* section has local
186                                                 * relocation entries */
187
188#define SECTION_ATTRIBUTES_USR   0xff000000UL   /* User setable attributes */
189#define S_ATTR_PURE_INSTRUCTIONS 0x80000000UL   /* only true machine insns */
190#define S_ATTR_NO_TOC            0x40000000UL   /* coalesced symbols that are
191                                                 * not to be in a ranlib table
192                                                 * of contents */
193#define S_ATTR_STRIP_STATIC_SYMS 0x20000000UL   /* ok to strip static symbols
194                                                 * in this section in files
195                                                 * with the MH_DYLDLINK flag */
196#define S_ATTR_NO_DEAD_STRIP     0x10000000UL   /* no dead stripping */
197#define S_ATTR_LIVE_SUPPORT      0x08000000UL   /* blocks are live if they
198                                                 * reference live blocks */
199#define S_ATTR_SELF_MODIFYING_CODE 0x04000000UL /* Used with i386 code stubs
200                                                 * written on by dyld */
201
202/* macho references symbols in different ways whether they are linked at
203 * runtime (LAZY, read library functions) or at link time (NON_LAZY, mostly
204 * data)
205 *
206 * TODO: proper support for dynamically linkable modules would require the
207 * __import sections as well as the dsymtab command
208 */
209#define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0x0
210#define REFERENCE_FLAG_UNDEFINED_LAZY     0x1
211
212#define align(x, y) \
213    (((x) + (y) - 1) & ~((y) - 1))      /* align x to multiple of y */
214
215#define align32(x) \
216    align(x, 4)                 /* align x to 32 bit boundary */
217
218#define macho_MAGIC     0x87654322
219
220/* Symbol table type field bit masks */
221#define N_STAB  0xe0            /* mask indicating stab entry */
222#define N_PEXT  0x10            /* private external bit */
223#define N_TYPE  0x0e            /* mask for all the type bits */
224#define N_EXT   0x01            /* external (global) bit */
225
226/* Symbol table type field values */
227#define N_UNDF  0x00            /* undefined */
228#define N_ABS   0x02            /* absolute address */
229#define N_SECT  0x0e            /* symbol is defined in a section */
230
231#define NO_SECT 0               /* no section for symbol in nlist */
232
233#define REGULAR_OUTBUF_SIZE     1024
234
235
236typedef struct macho_reloc {
237    yasm_reloc reloc;
238    int pcrel;
239    int length;
240    int ext;
241    enum reloc_type_x86_64 {
242        /* x86 relocations */
243        GENERIC_RELOC_VANILLA = 0,      /* generic relocation */
244        GENERIC_RELOC_PAIR = 1,         /* Only follows a GENERIC_RELOC_SECTDIFF */
245        GENERIC_RELOC_SECTDIFF = 2,
246        GENERIC_RELOC_PB_LA_PTR = 3,    /* prebound lazy pointer */
247        GENERIC_RELOC_LOCAL_SECTDIFF = 4,
248
249        /* x86-64 relocations */
250        X86_64_RELOC_UNSIGNED = 0,      /* for absolute addresses */
251        X86_64_RELOC_SIGNED = 1,        /* for signed 32-bit displacement */
252        X86_64_RELOC_BRANCH = 2,        /* a CALL/JMP insn with 32-bit disp */
253        X86_64_RELOC_GOT_LOAD = 3,      /* a MOVQ load of a GOT entry */
254        X86_64_RELOC_GOT = 4,           /* other GOT references */
255        X86_64_RELOC_SUBTRACTOR = 5,    /* must be followed by a X86_64_RELOC_UNSIGNED */
256        X86_64_RELOC_SIGNED_1 = 6,      /* signed 32-bit disp, -1 addend */
257        X86_64_RELOC_SIGNED_2 = 7,      /* signed 32-bit disp, -2 addend */
258        X86_64_RELOC_SIGNED_4 = 8       /* signed 32-bit disp, -4 addend */
259    } type;
260} macho_reloc;
261
262typedef struct macho_section_data {
263    /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
264    long scnum;                 /* section number (0=first section) */
265    /*@only@*/ char *segname;   /* segment name in file */
266    /*@only@*/ char *sectname;  /* section name in file */
267    unsigned long flags;        /* S_* flags */
268    unsigned long size;         /* size of raw data (section data) in bytes */
269    unsigned long offset;       /* offset in raw data within file in bytes */
270    unsigned long vmoff;        /* memory offset */
271    unsigned long nreloc;       /* number of relocation entries */
272    unsigned int extreloc;      /* external relocations present (0/1) */
273} macho_section_data;
274
275
276typedef struct macho_symrec_data {
277    unsigned long index;        /* index in output order */
278    yasm_intnum *value;         /* valid after writing symtable to file */
279    unsigned long length;       /* length + 1 (plus auto underscore) */
280} macho_symrec_data;
281
282
283typedef struct yasm_objfmt_macho {
284    yasm_objfmt_base objfmt;    /* base structure */
285
286    long parse_scnum;           /* sect numbering in parser */
287    int bits;                   /* 32 / 64 */
288
289    yasm_symrec *gotpcrel_sym;  /* ..gotpcrel */
290} yasm_objfmt_macho;
291
292
293typedef struct macho_objfmt_output_info {
294    yasm_object *object;
295    yasm_objfmt_macho *objfmt_macho;
296    yasm_errwarns *errwarns;
297    /*@dependent@ */ FILE *f;
298    /*@only@ */ unsigned char *buf;
299    yasm_section *sect;
300    /*@dependent@ */ macho_section_data *msd;
301
302    unsigned int is_64;         /* write object in 64 bit mode */
303
304    /* vmsize and filesize available after traversing section count routine */
305    unsigned long vmsize;       /* raw size of all sections (including BSS) */
306    unsigned long filesize;     /* size of sections in file (excluding BSS) */
307    unsigned long offset;       /* offset within file */
308
309    /* forward offset tracking */
310    unsigned long rel_base;     /* first relocation in file */
311    unsigned long s_reloff;     /* in-file offset to relocations */
312
313    unsigned long indx;         /* current symbol size in bytes (name length+1) */
314    unsigned long symindex;     /* current symbol index in output order */
315    int all_syms;               /* outputting all symbols? */
316    unsigned long strlength;    /* length of all strings */
317} macho_objfmt_output_info;
318
319
320static void macho_section_data_destroy(/*@only@*/ void *d);
321static void macho_section_data_print(void *data, FILE *f, int indent_level);
322
323static const yasm_assoc_data_callback macho_section_data_cb = {
324    macho_section_data_destroy,
325    macho_section_data_print
326};
327
328static void macho_symrec_data_destroy(/*@only@*/ void *d);
329static void macho_symrec_data_print(void *data, FILE *f, int indent_level);
330
331static const yasm_assoc_data_callback macho_symrec_data_cb = {
332    macho_symrec_data_destroy,
333    macho_symrec_data_print
334};
335
336yasm_objfmt_module yasm_macho_LTX_objfmt;
337yasm_objfmt_module yasm_macho32_LTX_objfmt;
338yasm_objfmt_module yasm_macho64_LTX_objfmt;
339
340static yasm_objfmt *
341macho_objfmt_create_common(yasm_object *object, yasm_objfmt_module *module,
342                           int bits_pref)
343{
344    yasm_objfmt_macho *objfmt_macho = yasm_xmalloc(sizeof(yasm_objfmt_macho));
345
346    objfmt_macho->objfmt.module = module;
347
348    /* Only support x86 arch for now */
349    if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
350        yasm_xfree(objfmt_macho);
351        return NULL;
352    }
353
354    /* Support x86 and amd64 machines of x86 arch */
355    if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0 &&
356        (bits_pref == 0 || bits_pref == 32)) {
357        objfmt_macho->bits = 32;
358        objfmt_macho->gotpcrel_sym = NULL;
359    } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
360                              "amd64") == 0 &&
361             (bits_pref == 0 || bits_pref == 64)) {
362        objfmt_macho->bits = 64;
363        /* FIXME: misuse of NULL bytecode */
364        objfmt_macho->gotpcrel_sym =
365            yasm_symtab_define_label(object->symtab, "..gotpcrel", NULL, 0, 0);
366    } else {
367        yasm_xfree(objfmt_macho);
368        return NULL;
369    }
370
371    objfmt_macho->parse_scnum = 0;      /* section numbering starts at 0 */
372    return (yasm_objfmt *)objfmt_macho;
373}
374
375static yasm_objfmt *
376macho_objfmt_create(yasm_object *object)
377{
378    yasm_objfmt *objfmt;
379    yasm_objfmt_macho *objfmt_macho;
380
381    objfmt = macho_objfmt_create_common(object, &yasm_macho_LTX_objfmt, 0);
382    if (objfmt) {
383        objfmt_macho = (yasm_objfmt_macho *)objfmt;
384        /* Figure out which bitness of object format to use */
385        if (objfmt_macho->bits == 32)
386            objfmt_macho->objfmt.module = &yasm_macho32_LTX_objfmt;
387        else if (objfmt_macho->bits == 64)
388            objfmt_macho->objfmt.module = &yasm_macho64_LTX_objfmt;
389    }
390    return objfmt;
391}
392
393static yasm_objfmt *
394macho32_objfmt_create(yasm_object *object)
395{
396    return macho_objfmt_create_common(object, &yasm_macho32_LTX_objfmt, 32);
397}
398
399static yasm_objfmt *
400macho64_objfmt_create(yasm_object *object)
401{
402    return macho_objfmt_create_common(object, &yasm_macho64_LTX_objfmt, 64);
403}
404
405static int
406macho_objfmt_output_value(yasm_value *value, unsigned char *buf,
407                          unsigned int destsize, unsigned long offset,
408                          yasm_bytecode *bc, int warn, /*@null@*/ void *d)
409{
410    /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
411    yasm_objfmt_macho *objfmt_macho;
412    /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
413    unsigned long intn_minus = 0, intn_plus = 0;
414    int retval;
415    unsigned int valsize = value->size;
416    macho_reloc *reloc = NULL;
417
418    assert(info != NULL);
419    objfmt_macho = info->objfmt_macho;
420
421    if (value->abs)
422        value->abs = yasm_expr_simplify(value->abs, 1);
423
424    /* Try to output constant and PC-relative section-local first.
425     * Note this does NOT output any value with a SEG, WRT, external,
426     * cross-section, or non-PC-relative reference (those are handled below).
427     */
428    switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
429                                    info->object->arch)) {
430        case -1:
431            return 1;
432        case 0:
433            break;
434        default:
435            return 0;
436    }
437
438    if (value->section_rel) {
439        yasm_error_set(YASM_ERROR_TOO_COMPLEX,
440            N_("macho: relocation too complex for current implementation"));
441        return 1;
442    }
443
444    if (value->rel) {
445        yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
446
447        reloc = yasm_xcalloc(sizeof(macho_reloc), 1);
448        reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
449        reloc->reloc.sym = value->rel;
450        switch (valsize) {
451            case 64:
452                reloc->length = 3;
453                break;
454            case 32:
455                reloc->length = 2;
456                break;
457            case 16:
458                reloc->length = 1;
459                break;
460            case 8:
461                reloc->length = 0;
462                break;
463            default:
464                yasm_error_set(YASM_ERROR_TOO_COMPLEX,
465                               N_("macho: relocation size unsupported"));
466                yasm_xfree(reloc);
467                return 1;
468        }
469        reloc->pcrel = 0;
470        reloc->ext = 0;
471        reloc->type = GENERIC_RELOC_VANILLA;
472        /* R_ABS */
473
474        if (value->rshift > 0) {
475            yasm_error_set(YASM_ERROR_TOO_COMPLEX,
476                           N_("macho: shifted relocations not supported"));
477            yasm_xfree(reloc);
478            return 1;
479        }
480
481        if (value->seg_of) {
482            yasm_error_set(YASM_ERROR_TOO_COMPLEX,
483                           N_("macho: SEG not supported"));
484            yasm_xfree(reloc);
485            return 1;
486        }
487
488        if (value->curpos_rel && objfmt_macho->gotpcrel_sym &&
489            value->wrt == objfmt_macho->gotpcrel_sym) {
490            reloc->type = X86_64_RELOC_GOT;
491            value->wrt = NULL;
492        } else if (value->wrt) {
493            yasm_error_set(YASM_ERROR_TOO_COMPLEX,
494                           N_("macho: invalid WRT"));
495            yasm_xfree(reloc);
496            return 1;
497        }
498
499        if (value->curpos_rel) {
500            reloc->pcrel = 1;
501            if (!info->is_64) {
502                /* Adjust to start of section, so subtract out the bytecode
503                 * offset.
504                 */
505                intn_minus = bc->offset;
506            } else {
507                /* Add in the offset plus value size to end up with 0. */
508                intn_plus = offset+destsize;
509                if (reloc->type == X86_64_RELOC_GOT) {
510                    /* XXX: This is a hack */
511                    if (offset >= 2 && buf[-2] == 0x8B)
512                        reloc->type = X86_64_RELOC_GOT_LOAD;
513                } else if (value->jump_target)
514                    reloc->type = X86_64_RELOC_BRANCH;
515                else
516                    reloc->type = X86_64_RELOC_SIGNED;
517            }
518        } else if (info->is_64) {
519            if (valsize == 32) {
520                yasm_error_set(YASM_ERROR_NOT_CONSTANT,
521                    N_("macho: sorry, cannot apply 32 bit absolute relocations in 64 bit mode, consider \"[_symbol wrt rip]\" for mem access, \"qword\" and \"dq _foo\" for pointers."));
522                return 1;
523            }
524            reloc->type = X86_64_RELOC_UNSIGNED;
525        }
526
527        /* It seems that x86-64 objects need to have all extern relocs? */
528        if (info->is_64)
529            reloc->ext = 1;
530
531        if ((vis & YASM_SYM_EXTERN) || (vis & YASM_SYM_COMMON)) {
532            reloc->ext = 1;
533            info->msd->extreloc = 1;    /* section has external relocations */
534        } else if (!info->is_64) {
535            /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
536
537            /* Local symbols need valued to their actual address */
538            if (yasm_symrec_get_label(value->rel, &sym_precbc)) {
539                yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
540                /*@null@*/ macho_section_data *msd;
541                msd = yasm_section_get_data(sym_sect, &macho_section_data_cb);
542                assert(msd != NULL);
543                intn_plus += msd->vmoff + yasm_bc_next_offset(sym_precbc);
544            }
545        }
546
547        info->msd->nreloc++;
548        /*printf("reloc %s type %d ",yasm_symrec_get_name(reloc->reloc.sym),reloc->type);*/
549        yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
550    }
551
552    if (intn_minus <= intn_plus)
553        intn = yasm_intnum_create_uint(intn_plus-intn_minus);
554    else {
555        intn = yasm_intnum_create_uint(intn_minus-intn_plus);
556        yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
557    }
558
559    if (value->abs) {
560        yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
561
562        if (!intn2) {
563            yasm_error_set(YASM_ERROR_TOO_COMPLEX,
564                           N_("macho: relocation too complex"));
565            yasm_intnum_destroy(intn);
566            return 1;
567        }
568        yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
569    }
570
571    retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
572                                      valsize, 0, bc, warn);
573    /*printf("val %ld\n",yasm_intnum_get_int(intn));*/
574    yasm_intnum_destroy(intn);
575    return retval;
576}
577
578static int
579macho_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
580{
581    /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
582    /*@null@*/ /*@only@*/ unsigned char *bigbuf;
583    unsigned long size = REGULAR_OUTBUF_SIZE;
584    int gap;
585
586    assert(info != NULL);
587
588    bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
589                             macho_objfmt_output_value, NULL);
590
591    /* Don't bother doing anything else if size ended up being 0. */
592    if (size == 0) {
593        if (bigbuf)
594            yasm_xfree(bigbuf);
595        return 0;
596    }
597
598    /* Warn that gaps are converted to 0 and write out the 0's. */
599    if (gap) {
600        unsigned long left;
601
602        yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
603                      N_("uninitialized space: zeroing"));
604        /* Write out in chunks */
605        memset(info->buf, 0, REGULAR_OUTBUF_SIZE);
606        left = size;
607        while (left > REGULAR_OUTBUF_SIZE) {
608            fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f);
609            left -= REGULAR_OUTBUF_SIZE;
610        }
611        fwrite(info->buf, left, 1, info->f);
612    } else {
613        /* Output buf (or bigbuf if non-NULL) to file */
614        fwrite(bigbuf ? bigbuf : info->buf, (size_t) size, 1, info->f);
615    }
616
617    /* If bigbuf was allocated, free it */
618    if (bigbuf)
619        yasm_xfree(bigbuf);
620
621    return 0;
622}
623
624static int
625macho_objfmt_output_section(yasm_section *sect, /*@null@ */ void *d)
626{
627    /*@null@ */ macho_objfmt_output_info *info =
628        (macho_objfmt_output_info *) d;
629    /*@dependent@ *//*@null@ */ macho_section_data *msd;
630
631    assert(info != NULL);
632    msd = yasm_section_get_data(sect, &macho_section_data_cb);
633    assert(msd != NULL);
634
635    if (!(msd->flags & S_ZEROFILL)) {
636        /* Output non-BSS sections */
637        info->sect = sect;
638        info->msd = msd;
639        yasm_section_bcs_traverse(sect, info->errwarns, info,
640                                  macho_objfmt_output_bytecode);
641    }
642    return 0;
643}
644
645static int
646macho_objfmt_output_relocs(yasm_section *sect, /*@null@*/ void *d)
647{
648    /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
649    /*@dependent@*/ /*@null@*/ macho_section_data *msd;
650    macho_reloc *reloc;
651
652    reloc = (macho_reloc *)yasm_section_relocs_first(sect);
653    while (reloc) {
654        unsigned char *localbuf = info->buf;
655        /*@null@*/ macho_symrec_data *xsymd;
656        unsigned long symnum;
657
658        xsymd = yasm_symrec_get_data(reloc->reloc.sym, &macho_symrec_data_cb);
659        yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
660        localbuf += 4;          /* address of relocation */
661
662        if (reloc->ext)
663            symnum = xsymd->index;
664        else {
665            /* find section where the symbol relates to */
666            /*@dependent@*/ /*@null@*/ yasm_section *dsect;
667            /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
668            symnum = 0; /* default to absolute */
669            if (yasm_symrec_get_label(reloc->reloc.sym, &precbc) &&
670                (dsect = yasm_bc_get_section(precbc)) &&
671                (msd = yasm_section_get_data(dsect, &macho_section_data_cb)))
672                symnum = msd->scnum+1;
673        }
674        YASM_WRITE_32_L(localbuf,
675                        (symnum & 0x00ffffff) |
676                        (((unsigned long)reloc->pcrel & 1) << 24) |
677                        (((unsigned long)reloc->length & 3) << 25) |
678                        (((unsigned long)reloc->ext & 1) << 27) |
679                        (((unsigned long)reloc->type & 0xf) << 28));
680        fwrite(info->buf, 8, 1, info->f);
681        reloc = (macho_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
682    }
683
684    return 0;
685}
686
687static int
688exp2_to_bits(unsigned long val)
689{
690    int ret = 0;
691
692    while (val) {
693        val >>= 1;
694        ret++;
695    }
696    ret = (ret > 0) ? ret - 1 : 0;
697
698    return ret;
699}
700
701static int
702macho_objfmt_is_section_label(yasm_symrec *sym)
703{
704    /*@dependent@*/ /*@null@*/ yasm_section *sect;
705    /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
706
707    /* Look at symrec for value/scnum/etc. */
708    if (yasm_symrec_get_label(sym, &precbc)) {
709        if (precbc)
710            sect = yasm_bc_get_section(precbc);
711        else
712            sect = NULL;
713        /* it's a label: get value and offset.
714         * If there is not a section, leave as debugging symbol.
715         */
716        if (sect) {
717            /*@dependent@*/ /*@null@*/ macho_section_data *msd;
718
719            msd = yasm_section_get_data(sect, &macho_section_data_cb);
720            if (msd) {
721                if (msd->sym == sym)
722                    return 1;   /* don't store section names */
723            }
724        }
725    }
726    return 0;
727}
728
729static int
730macho_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
731{
732    /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
733    yasm_objfmt_macho *objfmt_macho;
734    /*@dependent@*/ /*@null@*/ macho_section_data *msd;
735    unsigned char *localbuf;
736
737    assert(info != NULL);
738    objfmt_macho = info->objfmt_macho;
739    msd = yasm_section_get_data(sect, &macho_section_data_cb);
740    assert(msd != NULL);
741
742    localbuf = info->buf;
743
744    memset(localbuf, 0, 16);
745    strncpy((char *)localbuf, msd->sectname, 16);
746    localbuf += 16;
747    memset(localbuf, 0, 16);
748    strncpy((char *)localbuf, msd->segname, 16);
749    localbuf += 16;
750    /* section address, size depend on 32/64 bit mode */
751    YASM_WRITE_32_L(localbuf, msd->vmoff);      /* address in memory */
752    if (info->is_64)
753        YASM_WRITE_32_L(localbuf, 0);   /* 64-bit mode: upper 32 bits = 0 */
754    YASM_WRITE_32_L(localbuf, msd->size);       /* size in memory */
755    if (info->is_64)
756        YASM_WRITE_32_L(localbuf, 0);   /* 64-bit mode: upper 32 bits = 0 */
757
758    /* offset,align,reloff,nreloc,flags,reserved1,reserved2 are 32 bit */
759    if ((msd->flags & SECTION_TYPE) != S_ZEROFILL) {
760        YASM_WRITE_32_L(localbuf, msd->offset);
761        YASM_WRITE_32_L(localbuf, exp2_to_bits(yasm_section_get_align(sect)));
762        if (msd->nreloc) {
763            msd->flags |= S_ATTR_LOC_RELOC;
764            if (msd->extreloc)
765                msd->flags |= S_ATTR_EXT_RELOC;
766            YASM_WRITE_32_L(localbuf,
767                            align32((long)(info->rel_base + info->s_reloff)));
768            YASM_WRITE_32_L(localbuf, msd->nreloc);     /* nreloc */
769        } else {
770            YASM_WRITE_32_L(localbuf, 0);
771            YASM_WRITE_32_L(localbuf, 0);
772        }
773
774        info->s_reloff += msd->nreloc * MACHO_RELINFO_SIZE;     /* nreloc */
775    } else {
776        YASM_WRITE_32_L(localbuf, 0);   /* these are zero in BSS */
777        YASM_WRITE_32_L(localbuf, 0);
778        YASM_WRITE_32_L(localbuf, 0);
779        YASM_WRITE_32_L(localbuf, 0);
780    }
781
782    YASM_WRITE_32_L(localbuf, msd->flags);      /* flags */
783    YASM_WRITE_32_L(localbuf, 0);       /* reserved 1 */
784    YASM_WRITE_32_L(localbuf, 0);       /* reserved 2 */
785
786    if (info->is_64)
787        fwrite(info->buf, MACHO_SECTCMD64_SIZE, 1, info->f);
788    else
789        fwrite(info->buf, MACHO_SECTCMD_SIZE, 1, info->f);
790
791    return 0;
792}
793
794
795static int
796macho_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
797{
798    /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
799    /*@only@*/ char *name;
800    yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
801
802    assert(info != NULL);
803    if (info->all_syms ||
804        vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
805        if (0 == macho_objfmt_is_section_label(sym)) {
806            /* Save index in symrec data */
807            macho_symrec_data *sym_data =
808                yasm_symrec_get_data(sym, &macho_symrec_data_cb);
809            if (!sym_data) {
810                sym_data = yasm_xcalloc(sizeof(macho_symrec_data), 1);
811                yasm_symrec_add_data(sym, &macho_symrec_data_cb, sym_data);
812            }
813            sym_data->index = info->symindex;
814            info->symindex++;
815
816            name = yasm_symrec_get_global_name(sym, info->object);
817            /*printf("%s\n",name); */
818            /* name length + delimiter */
819            sym_data->length = (unsigned long)strlen(name) + 1;
820            info->strlength += sym_data->length;
821            info->indx++;
822            yasm_xfree(name);
823        }
824    }
825    return 0;
826}
827
828
829static int
830macho_objfmt_output_symtable(yasm_symrec *sym, /*@null@*/ void *d)
831{
832    /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
833    yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
834
835    assert(info != NULL);
836
837    if (info->all_syms ||
838        vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
839        const yasm_expr *equ_val;
840        const yasm_intnum *intn;
841        unsigned long value = 0;
842        long scnum = -3;        /* -3 = debugging symbol */
843        /*@dependent@*/ /*@null@*/ yasm_section *sect;
844        /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
845        unsigned char *localbuf;
846        yasm_intnum *val;
847        unsigned int long_int_bytes = (info->is_64) ? 8 : 4;
848        unsigned int n_type = 0, n_sect = 0, n_desc = 0;
849        macho_symrec_data *symd;
850
851        val = yasm_intnum_create_uint(0);
852
853        symd = yasm_symrec_get_data(sym, &macho_symrec_data_cb);
854
855        /* Look at symrec for value/scnum/etc. */
856        if (yasm_symrec_get_label(sym, &precbc)) {
857            if (precbc)
858                sect = yasm_bc_get_section(precbc);
859            else
860                sect = NULL;
861            /* it's a label: get value and offset.
862             * If there is not a section, leave as debugging symbol.
863             */
864            if (sect) {
865                /*@dependent@*/ /*@null@*/ macho_section_data *msd;
866
867                msd = yasm_section_get_data(sect, &macho_section_data_cb);
868                if (msd) {
869                    if (msd->sym == sym) {
870                        /* don't store section names */
871                        yasm_intnum_destroy(val);
872                        return 0;
873                    }
874                    scnum = msd->scnum;
875                    n_type = N_SECT;
876                } else
877                    yasm_internal_error(N_("didn't understand section"));
878                if (precbc)
879                    value += yasm_bc_next_offset(precbc);
880                /* all values are subject to correction: base offset is first
881                 * raw section, therefore add section offset
882                 */
883                if (msd)
884                    value += msd->vmoff;
885                yasm_intnum_set_uint(val, value);
886                /*printf("%s offset %lx\n",name,value);*/
887            }
888        } else if ((equ_val = yasm_symrec_get_equ(sym))) {
889            yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
890
891            intn = yasm_expr_get_intnum(&equ_val_copy, 1);
892            if (!intn) {
893                if (vis & YASM_SYM_GLOBAL) {
894                    yasm_error_set(YASM_ERROR_NOT_CONSTANT,
895                        N_("global EQU value not an integer expression"));
896                    yasm_errwarn_propagate(info->errwarns, equ_val->line);
897                }
898            } else
899                value = yasm_intnum_get_uint(intn);
900            yasm_expr_destroy(equ_val_copy);
901            yasm_intnum_set_uint(val, value);
902            n_type = N_ABS;
903            scnum = -2;         /* -2 = absolute symbol */
904        }
905
906        if (vis & YASM_SYM_EXTERN) {
907            n_type = N_EXT;
908            scnum = -1;
909            /*n_desc = REFERENCE_FLAG_UNDEFINED_LAZY;   * FIXME: see definition of REFERENCE_FLAG_* above */
910        } else if (vis & YASM_SYM_COMMON) {
911            yasm_expr **csize = yasm_symrec_get_common_size(sym);
912            n_type = N_UNDF | N_EXT;
913            if (csize) {
914                intn = yasm_expr_get_intnum(csize, 1);
915                if (!intn) {
916                    yasm_error_set(YASM_ERROR_NOT_CONSTANT,
917                                   N_("COMMON data size not an integer expression"));
918                    yasm_errwarn_propagate(info->errwarns, (*csize)->line);
919                } else
920                    yasm_intnum_set_uint(val, yasm_intnum_get_uint(intn));
921            }
922            /*printf("common symbol %s val %lu\n", name, yasm_intnum_get_uint(val));*/
923        } else if (vis & YASM_SYM_GLOBAL) {
924            yasm_valparamhead *valparams =
925                yasm_symrec_get_objext_valparams(sym);
926
927            struct macho_global_data {
928                unsigned long flag; /* N_PEXT */
929            } data;
930
931            data.flag = 0;
932
933            if (valparams) {
934                static const yasm_dir_help help[] = {
935                    { "private_extern", 0, yasm_dir_helper_flag_set,
936                      offsetof(struct macho_global_data, flag), N_PEXT },
937                };
938                yasm_dir_helper(sym, yasm_vps_first(valparams),
939                                yasm_symrec_get_decl_line(sym), help, NELEMS(help),
940                                &data, yasm_dir_helper_valparam_warn);
941            }
942
943            n_type |= N_EXT | data.flag;
944        }
945
946        localbuf = info->buf;
947        YASM_WRITE_32_L(localbuf, info->indx);  /* offset in string table */
948        YASM_WRITE_8(localbuf, n_type); /* type of symbol entry */
949        n_sect = (scnum >= 0) ? scnum + 1 : NO_SECT;
950        YASM_WRITE_8(localbuf, n_sect); /* referring section where symbol is found */
951        YASM_WRITE_16_L(localbuf, n_desc);      /* extra description */
952        yasm_intnum_get_sized(val, localbuf, long_int_bytes, ((long_int_bytes) << 3), 0, 0, 0); /* value/argument */
953        localbuf += long_int_bytes;
954        if (symd)
955            symd->value = val;
956        else
957            yasm_intnum_destroy(val);
958
959        info->indx += symd->length;
960
961        fwrite(info->buf, 8 + long_int_bytes, 1, info->f);
962    }
963
964    return 0;
965}
966
967
968static int
969macho_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
970{
971    /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
972    yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
973    /*@null@*/ macho_symrec_data *xsymd;
974
975
976    assert(info != NULL);
977
978    if (info->all_syms ||
979        vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
980        if (0 == macho_objfmt_is_section_label(sym)) {
981            /*@only@*/ char *name =
982                yasm_symrec_get_global_name(sym, info->object);
983            size_t len = strlen(name);
984
985            xsymd = yasm_symrec_get_data(sym, &macho_symrec_data_cb);
986            fwrite(name, len + 1, 1, info->f);
987            yasm_xfree(name);
988        }
989    }
990    return 0;
991}
992
993static int
994macho_objfmt_calc_sectsize(yasm_section *sect, /*@null@ */ void *d)
995{
996    /*@null@ */ macho_objfmt_output_info *info =
997        (macho_objfmt_output_info *) d;
998    /*@dependent@ *//*@null@ */ macho_section_data *msd;
999    unsigned long align;
1000
1001    assert(info != NULL);
1002    msd = yasm_section_get_data(sect, &macho_section_data_cb);
1003    assert(msd != NULL);
1004
1005    msd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
1006    if (!(msd->flags & S_ZEROFILL)) {
1007        msd->offset = info->offset;
1008        info->offset += msd->size;
1009        info->filesize += msd->size;
1010    }
1011
1012    /* accumulate size in memory */
1013    msd->vmoff = info->vmsize;
1014    info->vmsize += msd->size;
1015
1016    /* align both start and end of section */
1017    align = yasm_section_get_align(sect);
1018    if (align != 0) {
1019        unsigned long delta = msd->vmoff % align;
1020        if (delta > 0) {
1021            msd->vmoff += align - delta;
1022            info->vmsize += align - delta;
1023        }
1024    }
1025
1026    return 0;
1027}
1028
1029/* write object */
1030static void
1031macho_objfmt_output(yasm_object *object, FILE *f, int all_syms,
1032                    yasm_errwarns *errwarns)
1033{
1034    yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
1035    macho_objfmt_output_info info;
1036    unsigned char *localbuf;
1037    unsigned long symtab_count = 0;
1038    unsigned long headsize;
1039    unsigned int macho_segcmdsize, macho_sectcmdsize, macho_nlistsize;
1040    unsigned int macho_relinfosize, macho_segcmd;
1041    unsigned int head_ncmds, head_sizeofcmds;
1042    unsigned long fileoffset, fileoff_sections;
1043    yasm_intnum *val;
1044    unsigned long long_int_bytes;
1045    const char pad_data[3] = "\0\0\0";
1046
1047    info.object = object;
1048    info.objfmt_macho = objfmt_macho;
1049    info.errwarns = errwarns;
1050    info.f = f;
1051    info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
1052
1053    if (objfmt_macho->parse_scnum == 0) {
1054        yasm_internal_error(N_("no sections defined"));
1055        /*@notreached@*/
1056        return;
1057    }
1058
1059    val = yasm_intnum_create_uint(0);
1060
1061    /*
1062     * MACH-O Header, Seg CMD, Sect CMDs, Sym Tab, Reloc Data
1063     */
1064    info.is_64 = (objfmt_macho->bits == 32) ? 0 : 1;
1065    if (info.is_64) {
1066        /* this works only when SYMBOLS and SECTIONS present */
1067        headsize =
1068            MACHO_HEADER64_SIZE + MACHO_SEGCMD64_SIZE +
1069            (MACHO_SECTCMD64_SIZE * (objfmt_macho->parse_scnum)) +
1070            MACHO_SYMCMD_SIZE;
1071        macho_segcmd = LC_SEGMENT_64;
1072        macho_segcmdsize = MACHO_SEGCMD64_SIZE;
1073        macho_sectcmdsize = MACHO_SECTCMD64_SIZE;
1074        macho_nlistsize = MACHO_NLIST64_SIZE;
1075        macho_relinfosize = MACHO_RELINFO64_SIZE;
1076        long_int_bytes = 8;
1077    } else {
1078        headsize =
1079            MACHO_HEADER_SIZE + MACHO_SEGCMD_SIZE +
1080            (MACHO_SECTCMD_SIZE * (objfmt_macho->parse_scnum)) +
1081            MACHO_SYMCMD_SIZE;
1082        macho_segcmd = LC_SEGMENT;
1083        macho_segcmdsize = MACHO_SEGCMD_SIZE;
1084        macho_sectcmdsize = MACHO_SECTCMD_SIZE;
1085        macho_nlistsize = MACHO_NLIST_SIZE;
1086        macho_relinfosize = MACHO_RELINFO_SIZE;
1087        long_int_bytes = 4;
1088    }
1089
1090    /* Get number of symbols */
1091    info.symindex = 0;
1092    info.indx = 0;
1093    info.strlength = 1;         /* string table starts with a zero byte */
1094    info.all_syms = all_syms || info.is_64;
1095    /*info.all_syms = 1;                * force all syms into symbol table */
1096    yasm_symtab_traverse(object->symtab, &info, macho_objfmt_count_sym);
1097    symtab_count = info.indx;
1098
1099    /* write raw section data first */
1100    if (fseek(f, (long)headsize, SEEK_SET) < 0) {
1101        yasm__fatal(N_("could not seek on output file"));
1102        /*@notreached@ */
1103        return;
1104    }
1105
1106    /* get size of sections in memory (including BSS) and size of sections
1107     * in file (without BSS)
1108     */
1109    info.vmsize = 0;
1110    info.filesize = 0;
1111    info.offset = headsize;
1112    yasm_object_sections_traverse(object, &info, macho_objfmt_calc_sectsize);
1113
1114    /* output sections to file */
1115    yasm_object_sections_traverse(object, &info, macho_objfmt_output_section);
1116
1117    fileoff_sections = ftell(f);
1118
1119    /* Write headers */
1120    if (fseek(f, 0, SEEK_SET) < 0) {
1121        yasm__fatal(N_("could not seek on output file"));
1122        /*@notreached@*/
1123        return;
1124    }
1125
1126    localbuf = info.buf;
1127
1128    /* header size is common to 32 bit and 64 bit variants */
1129    if (info.is_64) {
1130        YASM_WRITE_32_L(localbuf, MH_MAGIC_64); /* magic number */
1131        /* i386 64-bit ABI */
1132        YASM_WRITE_32_L(localbuf, CPU_ARCH_ABI64 | CPU_TYPE_I386);
1133    } else {
1134        YASM_WRITE_32_L(localbuf, MH_MAGIC);    /* magic number */
1135        YASM_WRITE_32_L(localbuf, CPU_TYPE_I386);       /* i386 32-bit ABI */
1136    }
1137    /* i386 all cpu subtype compatible */
1138    YASM_WRITE_32_L(localbuf, CPU_SUBTYPE_I386_ALL);
1139    YASM_WRITE_32_L(localbuf, MH_OBJECT);       /* MACH file type */
1140
1141    /* calculate number of commands and their size, put to stream */
1142    head_ncmds = 0;
1143    head_sizeofcmds = 0;
1144    if (objfmt_macho->parse_scnum > 0) {
1145        head_ncmds++;
1146        head_sizeofcmds +=
1147            macho_segcmdsize + macho_sectcmdsize * objfmt_macho->parse_scnum;
1148    }
1149    if (symtab_count > 0) {
1150        head_ncmds++;
1151        head_sizeofcmds += MACHO_SYMCMD_SIZE;
1152    }
1153
1154    YASM_WRITE_32_L(localbuf, head_ncmds);
1155    YASM_WRITE_32_L(localbuf, head_sizeofcmds);
1156    YASM_WRITE_32_L(localbuf, 0);       /* no flags (yet) */
1157    if (info.is_64) {
1158        YASM_WRITE_32_L(localbuf, 0);   /* reserved in 64 bit */
1159        fileoffset = MACHO_HEADER64_SIZE + head_sizeofcmds;
1160    } else {
1161        /* initial offset to first section */
1162        fileoffset = MACHO_HEADER_SIZE + head_sizeofcmds;
1163    }
1164
1165    /* --------------- write segment header command ---------------- */
1166    YASM_WRITE_32_L(localbuf, macho_segcmd);    /* command LC_SEGMENT */
1167    /* size of load command including section load commands */
1168    YASM_WRITE_32_L(localbuf,
1169                    macho_segcmdsize +
1170                    macho_sectcmdsize * objfmt_macho->parse_scnum);
1171    /* in an MH_OBJECT file all sections are in one unnamed (name all zeros)
1172     * segment (16x0)
1173     */
1174    YASM_WRITE_32_L(localbuf, 0);
1175    YASM_WRITE_32_L(localbuf, 0);
1176    YASM_WRITE_32_L(localbuf, 0);
1177    YASM_WRITE_32_L(localbuf, 0);
1178
1179    /* in-memory offset, in-memory size */
1180    yasm_intnum_set_uint(val, 0);       /* offset in memory (vmaddr) */
1181    yasm_intnum_get_sized(val, localbuf, long_int_bytes,
1182                          ((long_int_bytes) << 3), 0, 0, 0);
1183    localbuf += long_int_bytes;
1184    yasm_intnum_set_uint(val, info.vmsize);     /* size in memory (vmsize) */
1185    yasm_intnum_get_sized(val, localbuf, long_int_bytes,
1186                          ((long_int_bytes) << 3), 0, 0, 0);
1187    localbuf += long_int_bytes;
1188    /* offset in file to first section */
1189    yasm_intnum_set_uint(val, fileoffset);
1190    yasm_intnum_get_sized(val, localbuf, long_int_bytes,
1191                          ((long_int_bytes) << 3), 0, 0, 0);
1192    localbuf += long_int_bytes;
1193    yasm_intnum_set_uint(val, info.filesize);   /* overall size in file */
1194    yasm_intnum_get_sized(val, localbuf, long_int_bytes,
1195                          ((long_int_bytes) << 3), 0, 0, 0);
1196    localbuf += long_int_bytes;
1197
1198    YASM_WRITE_32_L(localbuf, VM_PROT_DEFAULT); /* VM protection, maximum */
1199    YASM_WRITE_32_L(localbuf, VM_PROT_DEFAULT); /* VM protection, initial */
1200    /* number of sections */
1201    YASM_WRITE_32_L(localbuf, objfmt_macho->parse_scnum);
1202    YASM_WRITE_32_L(localbuf, 0);       /* no flags */
1203
1204    /* write MACH-O header and segment command to outfile */
1205    fwrite(info.buf, (size_t) (localbuf - info.buf), 1, f);
1206
1207    /* next: section headers */
1208    /* offset to relocs for first section */
1209    info.rel_base = align32((long)fileoff_sections);
1210    info.s_reloff = 0;          /* offset for relocs of following sections */
1211    yasm_object_sections_traverse(object, &info, macho_objfmt_output_secthead);
1212
1213    localbuf = info.buf;
1214    /* write out symbol command */
1215    YASM_WRITE_32_L(localbuf, LC_SYMTAB);       /* cmd == LC_SYMTAB */
1216    YASM_WRITE_32_L(localbuf, MACHO_SYMCMD_SIZE);
1217    /* symbol table offset */
1218    YASM_WRITE_32_L(localbuf, info.rel_base + info.s_reloff);
1219    YASM_WRITE_32_L(localbuf, symtab_count);    /* number of symbols */
1220
1221    YASM_WRITE_32_L(localbuf, macho_nlistsize * symtab_count + info.rel_base +
1222                    info.s_reloff);     /* string table offset */
1223    YASM_WRITE_32_L(localbuf, info.strlength);  /* string table size */
1224    /* write symbol command */
1225    fwrite(info.buf, (size_t)(localbuf - info.buf), 1, f);
1226
1227    /*printf("num symbols %d, vmsize %d, filesize %d\n",symtab_count,
1228      info.vmsize, info.filesize ); */
1229
1230    /* get back to end of raw section data */
1231    if (fseek(f, (long)fileoff_sections, SEEK_SET) < 0) {
1232        yasm__fatal(N_("could not seek on output file"));
1233        /*@notreached@*/
1234        return;
1235    }
1236
1237    /* padding to long boundary */
1238    if ((info.rel_base - fileoff_sections) > 0) {
1239        fwrite(pad_data, info.rel_base - fileoff_sections, 1, f);
1240    }
1241
1242    /* relocation data */
1243    yasm_object_sections_traverse(object, &info, macho_objfmt_output_relocs);
1244
1245    /* symbol table (NLIST) */
1246    info.indx = 1;              /* restart symbol table indices */
1247    yasm_symtab_traverse(object->symtab, &info, macho_objfmt_output_symtable);
1248
1249    /* symbol strings */
1250    fwrite(pad_data, 1, 1, f);
1251    yasm_symtab_traverse(object->symtab, &info, macho_objfmt_output_str);
1252
1253    yasm_intnum_destroy(val);
1254    yasm_xfree(info.buf);
1255}
1256
1257static void
1258macho_objfmt_destroy(yasm_objfmt *objfmt)
1259{
1260    yasm_xfree(objfmt);
1261}
1262
1263static void
1264macho_objfmt_init_new_section(yasm_section *sect, unsigned long line)
1265{
1266    yasm_object *object = yasm_section_get_object(sect);
1267    const char *sectname = yasm_section_get_name(sect);
1268    yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
1269    macho_section_data *data;
1270    yasm_symrec *sym;
1271
1272    data = yasm_xmalloc(sizeof(macho_section_data));
1273    data->scnum = objfmt_macho->parse_scnum++;
1274    data->segname = NULL;
1275    data->sectname = NULL;
1276    data->flags = S_REGULAR;
1277    data->size = 0;
1278    data->offset = 0;
1279    data->vmoff = 0;
1280    data->nreloc = 0;
1281    data->extreloc = 0;
1282    yasm_section_add_data(sect, &macho_section_data_cb, data);
1283
1284    sym = yasm_symtab_define_label(object->symtab, sectname,
1285                                   yasm_section_bcs_first(sect), 1, line);
1286    data->sym = sym;
1287}
1288
1289static yasm_section *
1290macho_objfmt_add_default_section(yasm_object *object)
1291{
1292    yasm_section *retval;
1293    macho_section_data *msd;
1294    int isnew;
1295
1296    retval = yasm_object_get_general(object, "LC_SEGMENT.__TEXT.__text", 0, 1,
1297                                     0, &isnew, 0);
1298    if (isnew) {
1299        msd = yasm_section_get_data(retval, &macho_section_data_cb);
1300        msd->segname = yasm__xstrdup("__TEXT");
1301        msd->sectname = yasm__xstrdup("__text");
1302        msd->flags = S_ATTR_PURE_INSTRUCTIONS;
1303        yasm_section_set_align(retval, 0, 0);
1304        yasm_section_set_default(retval, 1);
1305    }
1306    return retval;
1307}
1308
1309static /*@observer@*/ /*@null@*/ yasm_section *
1310macho_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
1311                            /*@unused@*/ /*@null@*/
1312                            yasm_valparamhead *objext_valparams,
1313                            unsigned long line)
1314{
1315    yasm_valparam *vp;
1316    yasm_section *retval;
1317    int isnew;
1318    /*@only@*/ char *f_sectname;
1319    unsigned long flags;
1320    unsigned long align;
1321    int flags_override = 0;
1322    const char *sectname;
1323    char *realname;
1324    int resonly = 0;
1325    macho_section_data *msd;
1326    size_t i;
1327
1328    static const struct {
1329        const char *in;
1330        const char *seg;
1331        const char *sect;
1332        unsigned long flags;
1333        unsigned long align;
1334    } section_name_translation[] = {
1335        {".text",           "__TEXT", "__text", S_ATTR_PURE_INSTRUCTIONS, 0},
1336        {".const",          "__TEXT", "__const",        S_REGULAR, 0},
1337        {".static_const",   "__TEXT", "__static_const", S_REGULAR, 0},
1338        {".cstring",        "__TEXT", "__cstring",      S_CSTRING_LITERALS, 0},
1339        {".literal4",       "__TEXT", "__literal4",     S_4BYTE_LITERALS, 4},
1340        {".literal8",       "__TEXT", "__literal8",     S_8BYTE_LITERALS, 8},
1341        {".literal16",      "__TEXT", "__literal16",    S_16BYTE_LITERALS, 16},
1342        {".constructor",    "__TEXT", "__constructor",  S_REGULAR, 0},
1343        {".destructor",     "__TEXT", "__destructor",   S_REGULAR, 0},
1344        {".fvmlib_init0",   "__TEXT", "__fvmlib_init0", S_REGULAR, 0},
1345        {".fvmlib_init1",   "__TEXT", "__fvmlib_init1", S_REGULAR, 0},
1346        {".mod_init_func",  "__DATA", "__mod_init_func",
1347            S_MOD_INIT_FUNC_POINTERS, 4},
1348        {".mod_term_func",  "__DATA", "__mod_term_func",
1349            S_MOD_TERM_FUNC_POINTERS, 4},
1350        {".dyld",           "__DATA", "__dyld",         S_REGULAR, 0},
1351        {".data",           "__DATA", "__data",         S_REGULAR, 0},
1352        {".static_data",    "__DATA", "__static_data",  S_REGULAR, 0},
1353        {".const_data",     "__DATA", "__const",        S_REGULAR, 0},
1354        {".rodata",         "__DATA", "__const",        S_REGULAR, 0},
1355        {".bss",            "__DATA", "__bss",          S_ZEROFILL, 0},
1356        {".objc_class_names",   "__TEXT", "__cstring",  S_CSTRING_LITERALS, 0},
1357        {".objc_meth_var_types","__TEXT", "__cstring",  S_CSTRING_LITERALS, 0},
1358        {".objc_meth_var_names","__TEXT", "__cstring",  S_CSTRING_LITERALS, 0},
1359        {".objc_selector_strs", "__OBJC", "__selector_strs",
1360            S_CSTRING_LITERALS, 0},
1361        {".objc_class",         "__OBJC", "__class",
1362            S_ATTR_NO_DEAD_STRIP, 0},
1363        {".objc_meta_class",    "__OBJC", "__meta_class",
1364            S_ATTR_NO_DEAD_STRIP, 0},
1365        {".objc_string_object", "__OBJC", "__string_object",
1366            S_ATTR_NO_DEAD_STRIP, 0},
1367        {".objc_protocol",      "__OBJC", "__protocol",
1368            S_ATTR_NO_DEAD_STRIP, 0},
1369        {".objc_cat_cls_meth",  "__OBJC", "__cat_cls_meth",
1370            S_ATTR_NO_DEAD_STRIP, 0},
1371        {".objc_cat_inst_meth", "__OBJC", "__cat_inst_meth",
1372            S_ATTR_NO_DEAD_STRIP, 0},
1373        {".objc_cls_meth",      "__OBJC", "__cls_meth",
1374            S_ATTR_NO_DEAD_STRIP, 0},
1375        {".objc_inst_meth",     "__OBJC", "__inst_meth",
1376            S_ATTR_NO_DEAD_STRIP, 0},
1377        {".objc_message_refs",  "__OBJC", "__message_refs",
1378            S_LITERAL_POINTERS|S_ATTR_NO_DEAD_STRIP, 4},
1379        {".objc_cls_refs",      "__OBJC", "__cls_refs",
1380            S_LITERAL_POINTERS|S_ATTR_NO_DEAD_STRIP, 4},
1381        {".objc_module_info",   "__OBJC", "__module_info",
1382            S_ATTR_NO_DEAD_STRIP, 0},
1383        {".objc_symbols",       "__OBJC", "__symbols",
1384            S_ATTR_NO_DEAD_STRIP, 0},
1385        {".objc_category",      "__OBJC", "__category",
1386            S_ATTR_NO_DEAD_STRIP, 0},
1387        {".objc_class_vars",    "__OBJC", "__class_vars",
1388            S_ATTR_NO_DEAD_STRIP, 0},
1389        {".objc_instance_vars", "__OBJC", "__instance_vars",
1390            S_ATTR_NO_DEAD_STRIP, 0}
1391    };
1392
1393    struct macho_section_switch_data {
1394        /*@only@*/ /*@null@*/ char *f_segname;
1395        /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
1396    } data;
1397
1398    static const yasm_dir_help help[] = {
1399        { "segname", 1, yasm_dir_helper_string,
1400          offsetof(struct macho_section_switch_data, f_segname), 0 },
1401        { "align", 1, yasm_dir_helper_intn,
1402          offsetof(struct macho_section_switch_data, align_intn), 0 }
1403    };
1404
1405    data.f_segname = NULL;
1406    data.align_intn = NULL;
1407
1408    vp = yasm_vps_first(valparams);
1409    sectname = yasm_vp_string(vp);
1410    if (!sectname)
1411        return NULL;
1412    vp = yasm_vps_next(vp);
1413
1414    /* translate .text,.data,.bss to __text,__data,__bss... */
1415    for (i=0; i<NELEMS(section_name_translation); i++) {
1416        if (yasm__strcasecmp(sectname, section_name_translation[i].in) == 0)
1417            break;
1418    }
1419
1420    if (i == NELEMS(section_name_translation)) {
1421        const char *s;
1422        if (vp && !vp->val && (s = yasm_vp_string(vp))) {
1423            /* Treat as SEGNAME, SECTNAME */
1424            if (strlen(sectname) > 16)
1425                yasm_warn_set(YASM_WARN_GENERAL,
1426                    N_("segment name is too long, max 16 chars; truncating"));
1427            data.f_segname = yasm__xstrndup(sectname, 16);
1428            if (strlen(s) > 16)
1429                yasm_warn_set(YASM_WARN_GENERAL,
1430                    N_("section name is too long, max 16 chars; truncating"));
1431            f_sectname = yasm__xstrndup(s, 16);
1432            flags = S_REGULAR;
1433            align = 0;
1434
1435            sectname = s;
1436            vp = yasm_vps_next(vp);
1437        } else {
1438            data.f_segname = NULL;
1439            if (strlen(sectname) > 16)
1440                yasm_warn_set(YASM_WARN_GENERAL,
1441                    N_("section name is too long, max 16 chars; truncating"));
1442            f_sectname = yasm__xstrndup(sectname, 16);
1443            flags = S_ATTR_SOME_INSTRUCTIONS;
1444            align = 0;
1445        }
1446    } else {
1447        data.f_segname = yasm__xstrdup(section_name_translation[i].seg);
1448        f_sectname = yasm__xstrdup(section_name_translation[i].sect);
1449        flags = section_name_translation[i].flags;
1450        align = section_name_translation[i].align;
1451    }
1452
1453    flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
1454                                     &data, yasm_dir_helper_valparam_warn);
1455    if (flags_override < 0)
1456        return NULL;    /* error occurred */
1457
1458    if (data.align_intn) {
1459        align = yasm_intnum_get_uint(data.align_intn);
1460        yasm_intnum_destroy(data.align_intn);
1461
1462        /* Alignments must be a power of two. */
1463        if (!is_exp2(align)) {
1464            yasm_error_set(YASM_ERROR_VALUE,
1465                           N_("argument to `%s' is not a power of two"),
1466                           vp->val);
1467            return NULL;
1468        }
1469
1470        /* Check to see if alignment is supported size */
1471        if (align > 16384) {
1472            yasm_error_set(YASM_ERROR_VALUE,
1473                N_("macho implementation does not support alignments > 16384"));
1474            return NULL;
1475        }
1476    }
1477
1478    if (!data.f_segname) {
1479        yasm_warn_set(YASM_WARN_GENERAL,
1480                      N_("Unknown section name, defaulting to __TEXT segment"));
1481        data.f_segname = yasm__xstrdup("__TEXT");
1482    }
1483
1484    /* Build a unique sectname from f_segname and f_sectname. */
1485    realname = yasm_xmalloc(strlen("LC_SEGMENT") + 1 + strlen(data.f_segname) + 1 +
1486                            strlen(f_sectname) + 1);
1487    sprintf(realname, "LC_SEGMENT.%s.%s", data.f_segname, f_sectname);
1488    retval = yasm_object_get_general(object, realname, align, 1, resonly,
1489                                     &isnew, line);
1490    yasm_xfree(realname);
1491
1492    msd = yasm_section_get_data(retval, &macho_section_data_cb);
1493
1494    if (isnew || yasm_section_is_default(retval)) {
1495        yasm_section_set_default(retval, 0);
1496        msd->segname = data.f_segname;
1497        msd->sectname = f_sectname;
1498        msd->flags = flags;
1499        yasm_section_set_align(retval, align, line);
1500    } else if (flags_override) {
1501        /* align is the only value used from overrides. */
1502        if (yasm_section_get_align(retval) != align) {
1503            yasm_warn_set(YASM_WARN_GENERAL,
1504                          N_("section flags ignored on section redeclaration"));
1505        }
1506    }
1507    return retval;
1508}
1509
1510static /*@observer@*/ /*@null@*/ yasm_symrec *
1511macho_objfmt_get_special_sym(yasm_object *object, const char *name,
1512                             const char *parser)
1513{
1514    yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
1515    if (yasm__strcasecmp(name, "gotpcrel") == 0) {
1516        return objfmt_macho->gotpcrel_sym;
1517    }
1518    return NULL;
1519}
1520
1521static void
1522macho_section_data_destroy(void *data)
1523{
1524    macho_section_data *msd = (macho_section_data *) data;
1525    yasm_xfree(msd->segname);
1526    yasm_xfree(msd->sectname);
1527    yasm_xfree(data);
1528}
1529
1530static void
1531macho_section_data_print(void *data, FILE *f, int indent_level)
1532{
1533    macho_section_data *msd = (macho_section_data *) data;
1534
1535    fprintf(f, "%*ssym=\n", indent_level, "");
1536    yasm_symrec_print(msd->sym, f, indent_level + 1);
1537    fprintf(f, "%*sscnum=%ld\n", indent_level, "", msd->scnum);
1538    fprintf(f, "%*sflags=0x%lx\n", indent_level, "", msd->flags);
1539    fprintf(f, "%*ssize=%lu\n", indent_level, "", msd->size);
1540    fprintf(f, "%*snreloc=%lu\n", indent_level, "", msd->nreloc);
1541    fprintf(f, "%*soffset=%lu\n", indent_level, "", msd->offset);
1542    fprintf(f, "%*sextreloc=%u\n", indent_level, "", msd->extreloc);
1543}
1544
1545static void
1546macho_symrec_data_destroy(void *data)
1547{
1548    yasm_xfree(data);
1549}
1550
1551static void
1552macho_symrec_data_print(void *data, FILE *f, int indent_level)
1553{
1554    macho_symrec_data *msd = (macho_symrec_data *)data;
1555
1556    fprintf(f, "%*sindex=%ld\n", indent_level, "", msd->index);
1557    fprintf(f, "%*svalue=", indent_level, "");
1558    if (msd->value)
1559        fprintf(f, "%ld\n", yasm_intnum_get_int(msd->value));
1560    else
1561        fprintf(f, "nil\n");
1562}
1563
1564
1565/* Define valid debug formats to use with this object format */
1566static const char *macho_objfmt_dbgfmt_keywords[] = {
1567    "null",
1568    NULL
1569};
1570
1571/* Define objfmt structure -- see objfmt.h for details */
1572yasm_objfmt_module yasm_macho_LTX_objfmt = {
1573    "Mac OS X ABI Mach-O File Format",
1574    "macho",
1575    "o",
1576    32,
1577    0,
1578    macho_objfmt_dbgfmt_keywords,
1579    "null",
1580    NULL,   /* no directives */
1581    NULL,   /* no standard macros */
1582    macho_objfmt_create,
1583    macho_objfmt_output,
1584    macho_objfmt_destroy,
1585    macho_objfmt_add_default_section,
1586    macho_objfmt_init_new_section,
1587    macho_objfmt_section_switch,
1588    macho_objfmt_get_special_sym
1589};
1590
1591yasm_objfmt_module yasm_macho32_LTX_objfmt = {
1592    "Mac OS X ABI Mach-O File Format (32-bit)",
1593    "macho32",
1594    "o",
1595    32,
1596    0,
1597    macho_objfmt_dbgfmt_keywords,
1598    "null",
1599    NULL,   /* no directives */
1600    NULL,   /* no standard macros */
1601    macho32_objfmt_create,
1602    macho_objfmt_output,
1603    macho_objfmt_destroy,
1604    macho_objfmt_add_default_section,
1605    macho_objfmt_init_new_section,
1606    macho_objfmt_section_switch,
1607    macho_objfmt_get_special_sym
1608};
1609
1610yasm_objfmt_module yasm_macho64_LTX_objfmt = {
1611    "Mac OS X ABI Mach-O File Format (64-bit)",
1612    "macho64",
1613    "o",
1614    64,
1615    0,
1616    macho_objfmt_dbgfmt_keywords,
1617    "null",
1618    NULL,   /* no directives */
1619    NULL,   /* no standard macros */
1620    macho64_objfmt_create,
1621    macho_objfmt_output,
1622    macho_objfmt_destroy,
1623    macho_objfmt_add_default_section,
1624    macho_objfmt_init_new_section,
1625    macho_objfmt_section_switch,
1626    macho_objfmt_get_special_sym
1627};
1628