1 /**
2  * Generate Mach-O object files
3  *
4  * Compiler implementation of the
5  * $(LINK2 https://www.dlang.org, D programming language).
6  *
7  * Copyright:   Copyright (C) 2009-2023 by The D Language Foundation, All Rights Reserved
8  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
9  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
10  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/machobj.d, backend/machobj.d)
11  */
12 
13 module dmd.backend.machobj;
14 
15 import core.stdc.ctype;
16 import core.stdc.stdint;
17 import core.stdc.stdio;
18 import core.stdc.stdlib;
19 import core.stdc.string;
20 
21 import dmd.backend.barray;
22 import dmd.backend.cc;
23 import dmd.backend.cdef;
24 import dmd.backend.code;
25 import dmd.backend.code_x86;
26 import dmd.backend.mem;
27 import dmd.backend.aarray;
28 import dmd.backend.dlist;
29 import dmd.backend.el;
30 import dmd.backend.global;
31 import dmd.backend.obj;
32 import dmd.backend.oper;
33 import dmd.backend.ty;
34 import dmd.backend.type;
35 
36 import dmd.common.outbuffer;
37 
38 nothrow:
39 @safe:
40 
41 alias _compare_fp_t = extern(C) nothrow int function(const void*, const void*);
42 extern(C) void qsort(void* base, size_t nmemb, size_t size, _compare_fp_t compar);
43 
44 import dmd.backend.dwarf;
45 import dmd.backend.mach;
46 
47 alias nlist = dmd.backend.mach.nlist;   // avoid conflict with dmd.backend.dlist.nlist
48 
49 /****************************************
50  * Sort the relocation entry buffer.
51  * put before nothrow because qsort was not marked nothrow until version 2.086
52  */
53 
54 extern (C) {
55 @trusted
56 private int mach_rel_fp(scope const(void*) e1, scope const(void*) e2)
57 {   Relocation *r1 = cast(Relocation *)e1;
58     Relocation *r2 = cast(Relocation *)e2;
59 
60     return cast(int)(r1.offset - r2.offset);
61 }
62 }
63 
64 @trusted
65 void mach_relsort(OutBuffer *buf)
66 {
67     qsort(buf.buf, buf.length() / Relocation.sizeof, Relocation.sizeof, &mach_rel_fp);
68 }
69 
70 // for x86_64
71 enum
72 {
73     X86_64_RELOC_UNSIGNED         = 0,
74     X86_64_RELOC_SIGNED           = 1,
75     X86_64_RELOC_BRANCH           = 2,
76     X86_64_RELOC_GOT_LOAD         = 3,
77     X86_64_RELOC_GOT              = 4,
78     X86_64_RELOC_SUBTRACTOR       = 5,
79     X86_64_RELOC_SIGNED_1         = 6,
80     X86_64_RELOC_SIGNED_2         = 7,
81     X86_64_RELOC_SIGNED_4         = 8,
82     X86_64_RELOC_TLV              = 9, // for thread local variables
83 }
84 
85 private extern (D) __gshared OutBuffer *fobjbuf;
86 
87 enum DEST_LEN = (IDMAX + IDOHD + 1);
88 
89 public import dmd.backend.dwarfdbginf : except_table_seg, eh_frame_seg;
90 
91 /******************************************
92  */
93 
94 /// Returns: a reference to the global offset table
95 @trusted
96 Symbol* MachObj_getGOTsym()
97 {
98     __gshared Symbol *GOTsym;
99     if (!GOTsym)
100     {
101         GOTsym = symbol_name("_GLOBAL_OFFSET_TABLE_",SC.global,tspvoid);
102     }
103     return GOTsym;
104 }
105 
106 void MachObj_refGOTsym()
107 {
108     assert(0);
109 }
110 
111 // The object file is built is several separate pieces
112 
113 
114 // String Table  - String table for all other names
115 private extern (D) __gshared OutBuffer *symtab_strings;
116 
117 // Section Headers
118 __gshared OutBuffer  *SECbuf;             // Buffer to build section table in
119 @trusted
120 section* SecHdrTab() { return cast(section *)SECbuf.buf; }
121 @trusted
122 section_64* SecHdrTab64() { return cast(section_64 *)SECbuf.buf; }
123 
124 __gshared
125 {
126 
127 // The relocation for text and data seems to get lost.
128 // Try matching the order gcc output them
129 // This means defining the sections and then removing them if they are
130 // not used.
131 private int section_cnt;         // Number of sections in table
132 enum SEC_TAB_INIT = 16;          // Initial number of sections in buffer
133 enum SEC_TAB_INC  = 4;           // Number of sections to increment buffer by
134 
135 enum SYM_TAB_INIT = 100;         // Initial number of symbol entries in buffer
136 enum SYM_TAB_INC  = 50;          // Number of symbols to increment buffer by
137 
138 /* Three symbol tables, because the different types of symbols
139  * are grouped into 3 different types (and a 4th for comdef's).
140  */
141 
142 private OutBuffer *local_symbuf;
143 private OutBuffer *public_symbuf;
144 private OutBuffer *extern_symbuf;
145 }
146 
147 @trusted
148 private void reset_symbols(OutBuffer *buf)
149 {
150     Symbol **p = cast(Symbol **)buf.buf;
151     const size_t n = buf.length() / (Symbol *).sizeof;
152     for (size_t i = 0; i < n; ++i)
153         symbol_reset(p[i]);
154 }
155 
156 __gshared
157 {
158 
159 struct Comdef { Symbol *sym; targ_size_t size; int count; }
160 private OutBuffer *comdef_symbuf;        // Comdef's are stored here
161 
162 private OutBuffer *indirectsymbuf1;      // indirect symbol table of Symbol*'s
163 private int jumpTableSeg;                // segment index for __jump_table
164 
165 private OutBuffer *indirectsymbuf2;      // indirect symbol table of Symbol*'s
166 private int pointersSeg;                 // segment index for __pointers
167 
168 /* If an MachObj_external_def() happens, set this to the string index,
169  * to be added last to the symbol table.
170  * Obviously, there can be only one.
171  */
172 private IDXSTR extdef;
173 }
174 
175 static if (0)
176 {
177 enum
178 {
179     STI_FILE  = 1,            // Where file symbol table entry is
180     STI_TEXT  = 2,
181     STI_DATA  = 3,
182     STI_BSS   = 4,
183     STI_GCC   = 5,            // Where "gcc2_compiled" symbol is */
184     STI_RODAT = 6,            // Symbol for readonly data
185     STI_COM   = 8,
186 }
187 }
188 
189 // Each compiler segment is a section
190 // Predefined compiler segments CODE,DATA,CDATA,UDATA map to indexes
191 //      into SegData[]
192 //      New compiler segments are added to end.
193 
194 /******************************
195  * Returns !=0 if this segment is a code segment.
196  */
197 @trusted
198 int mach_seg_data_isCode(const ref seg_data sd)
199 {
200     // The codegen assumes that code.data references are indirect,
201     // but when CDATA is treated as code reftoident will emit a direct
202     // relocation.
203     if (&sd == SegData[CDATA])
204         return false;
205 
206     if (I64)
207     {
208         //printf("SDshtidx = %d, x%x\n", SDshtidx, SecHdrTab64[sd.SDshtidx].flags);
209         return strcmp(SecHdrTab64[sd.SDshtidx].segname.ptr, "__TEXT") == 0;
210     }
211     else
212     {
213         //printf("SDshtidx = %d, x%x\n", SDshtidx, SecHdrTab[sd.SDshtidx].flags);
214         return strcmp(SecHdrTab[sd.SDshtidx].segname.ptr, "__TEXT") == 0;
215     }
216 }
217 
218 
219 __gshared
220 {
221 extern (C++) extern Rarray!(seg_data*) SegData;
222 
223 /**
224  * Section index for the __thread_vars/__tls_data section.
225  *
226  * This section is used for the variable symbol for TLS variables.
227  */
228 private extern (D) int seg_tlsseg = UNKNOWN;
229 
230 /**
231  * Section index for the __thread_bss section.
232  *
233  * This section is used for the data symbol ($tlv$init) for TLS variables
234  * without an initializer.
235  */
236 private extern (D) int seg_tlsseg_bss = UNKNOWN;
237 
238 /**
239  * Section index for the __thread_data section.
240  *
241  * This section is used for the data symbol ($tlv$init) for TLS variables
242  * with an initializer.
243  */
244 int seg_tlsseg_data = UNKNOWN;
245 
246 int seg_cstring = UNKNOWN;        // __cstring section
247 int seg_mod_init_func = UNKNOWN;  // __mod_init_func section
248 int seg_mod_term_func = UNKNOWN;  // __mod_term_func section
249 int seg_deh_eh = UNKNOWN;         // __deh_eh section
250 int seg_textcoal_nt = UNKNOWN;
251 int seg_tlscoal_nt = UNKNOWN;
252 int seg_datacoal_nt = UNKNOWN;
253 }
254 
255 /*******************************************************
256  * Because the Mach-O relocations cannot be computed until after
257  * all the segments are written out, and we need more information
258  * than the Mach-O relocations provide, make our own relocation
259  * type. Later, translate to Mach-O relocation structure.
260  */
261 
262 enum
263 {
264     RELaddr = 0,      // straight address
265     RELrel  = 1,      // relative to location to be fixed up
266 }
267 
268 struct Relocation
269 {   // Relocations are attached to the struct seg_data they refer to
270     targ_size_t offset; // location in segment to be fixed up
271     Symbol *funcsym;    // function in which offset lies, if any
272     Symbol *targsym;    // if !=null, then location is to be fixed up
273                         // to address of this symbol
274     uint targseg;       // if !=0, then location is to be fixed up
275                         // to address of start of this segment
276     ubyte rtype;        // RELaddr or RELrel
277     ubyte flag;         // 1: emit SUBTRACTOR/UNSIGNED pair
278     short val;          // 0, -1, -2, -4
279 }
280 
281 
282 /*******************************
283  * Output a string into a string table
284  * Input:
285  *      strtab  =       string table for entry
286  *      str     =       string to add
287  *
288  * Returns index into the specified string table.
289  */
290 @trusted
291 IDXSTR MachObj_addstr(OutBuffer *strtab, const(char)* str)
292 {
293     //printf("MachObj_addstr(strtab = %p str = '%s')\n",strtab,str);
294     IDXSTR idx = cast(IDXSTR)strtab.length();        // remember starting offset
295     strtab.writeStringz(str);
296     //printf("\tidx %d, new size %d\n",idx,strtab.length());
297     return idx;
298 }
299 
300 /*******************************
301  * Output a mangled string into the symbol string table
302  * Input:
303  *      str     =       string to add
304  *
305  * Returns index into the table.
306  */
307 @trusted
308 private IDXSTR mach_addmangled(Symbol *s)
309 {
310     //printf("mach_addmangled(%s)\n", s.Sident);
311     char[DEST_LEN] dest = void;
312     char *destr;
313     const(char)* name;
314     IDXSTR namidx;
315 
316     namidx = cast(IDXSTR)symtab_strings.length();
317     destr = obj_mangle2(s, dest.ptr);
318     name = destr;
319     if (CPP && name[0] == '_' && name[1] == '_')
320     {
321         if (strncmp(name,"__ct__",6) == 0)
322             name += 4;
323 static if (0)
324 {
325         switch(name[2])
326         {
327             case 'c':
328                 if (strncmp(name,"__ct__",6) == 0)
329                     name += 4;
330                 break;
331             case 'd':
332                 if (strcmp(name,"__dl__FvP") == 0)
333                     name = "__builtin_delete";
334                 break;
335             case 'v':
336                 //if (strcmp(name,"__vec_delete__FvPiUIPi") == 0)
337                     //name = "__builtin_vec_del";
338                 //else
339                 //if (strcmp(name,"__vn__FPUI") == 0)
340                     //name = "__builtin_vec_new";
341                 break;
342             case 'n':
343                 if (strcmp(name,"__nw__FPUI") == 0)
344                     name = "__builtin_new";
345                 break;
346 
347             default:
348                 break;
349         }
350 }
351     }
352     else if (tyfunc(s.ty()) && s.Sfunc && s.Sfunc.Fredirect)
353         name = s.Sfunc.Fredirect;
354     symtab_strings.writeStringz(name);
355     if (destr != dest.ptr)                  // if we resized result
356         mem_free(destr);
357     //dbg_printf("\telf_addmagled symtab_strings %s namidx %d len %d size %d\n",name, namidx,len,symtab_strings.length());
358     return namidx;
359 }
360 
361 /**************************
362  * Ouput read only data and generate a symbol for it.
363  *
364  */
365 
366 Symbol * MachObj_sym_cdata(tym_t ty,char *p,int len)
367 {
368     Symbol *s;
369 
370 static if (0)
371 {
372     if (I64)
373     {
374         alignOffset(DATA, tysize(ty));
375         s = symboldata(Offset(DATA), ty);
376         SegData[DATA].SDbuf.write(p,len);
377         s.Sseg = DATA;
378         s.Soffset = Offset(DATA);   // Remember its offset into DATA section
379         Offset(DATA) += len;
380 
381         s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern;
382         return s;
383     }
384 }
385     //printf("MachObj_sym_cdata(ty = %x, p = %x, len = %d, Offset(CDATA) = %x)\n", ty, p, len, Offset(CDATA));
386     alignOffset(CDATA, tysize(ty));
387     s = symboldata(Offset(CDATA), ty);
388     s.Sseg = CDATA;
389     //MachObj_pubdef(CDATA, s, Offset(CDATA));
390     MachObj_bytes(CDATA, Offset(CDATA), len, p);
391 
392     s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern;
393     return s;
394 }
395 
396 /**************************
397  * Ouput read only data for data
398  *
399  */
400 @trusted
401 int MachObj_data_readonly(char *p, int len, int *pseg)
402 {
403     int oldoff = cast(int)Offset(CDATA);
404     SegData[CDATA].SDbuf.reserve(len);
405     SegData[CDATA].SDbuf.writen(p,len);
406     Offset(CDATA) += len;
407     *pseg = CDATA;
408     return oldoff;
409 }
410 
411 @trusted
412 int MachObj_data_readonly(char *p, int len)
413 {
414     int pseg;
415 
416     return MachObj_data_readonly(p, len, &pseg);
417 }
418 
419 /*****************************
420  * Get segment for readonly string literals.
421  * The linker will pool strings in this section.
422  * Params:
423  *    sz = number of bytes per character (1, 2, or 4)
424  * Returns:
425  *    segment index
426  */
427 @trusted
428 int MachObj_string_literal_segment(uint sz)
429 {
430     if (sz == 1)
431         return getsegment2(seg_cstring, "__cstring", "__TEXT", 0, S_CSTRING_LITERALS);
432 
433     return CDATA;  // no special handling for other wstring, dstring; use __const
434 }
435 
436 /******************************
437  * Perform initialization that applies to all .o output files.
438  *      Called before any other obj_xxx routines
439  */
440 @system
441 Obj MachObj_init(OutBuffer *objbuf, const(char)* filename, const(char)* csegname)
442 {
443     //printf("MachObj_init()\n");
444     Obj obj = cast(Obj)mem_calloc(__traits(classInstanceSize, Obj));
445 
446     cseg = CODE;
447     fobjbuf = objbuf;
448 
449     seg_tlsseg = UNKNOWN;
450     seg_tlsseg_bss = UNKNOWN;
451     seg_tlsseg_data = UNKNOWN;
452     seg_cstring = UNKNOWN;
453     seg_mod_init_func = UNKNOWN;
454     seg_mod_term_func = UNKNOWN;
455     seg_deh_eh = UNKNOWN;
456     seg_textcoal_nt = UNKNOWN;
457     seg_tlscoal_nt = UNKNOWN;
458     seg_datacoal_nt = UNKNOWN;
459 
460     // Initialize buffers
461 
462     if (symtab_strings)
463         symtab_strings.setsize(1);
464     else
465     {
466         symtab_strings = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
467         if (!symtab_strings)
468             err_nomem();
469         symtab_strings.reserve(2048);
470         symtab_strings.writeByte(0);
471     }
472 
473     if (!local_symbuf)
474     {
475         local_symbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
476         if (!local_symbuf)
477             err_nomem();
478         local_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
479     }
480     local_symbuf.reset();
481 
482     if (public_symbuf)
483     {
484         reset_symbols(public_symbuf);
485         public_symbuf.reset();
486     }
487     else
488     {
489         public_symbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
490         if (!public_symbuf)
491             err_nomem();
492         public_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
493     }
494 
495     if (extern_symbuf)
496     {
497         reset_symbols(extern_symbuf);
498         extern_symbuf.reset();
499     }
500     else
501     {
502         extern_symbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
503         if (!extern_symbuf)
504             err_nomem();
505         extern_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
506     }
507 
508     if (!comdef_symbuf)
509     {
510         comdef_symbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
511         if (!comdef_symbuf)
512             err_nomem();
513         comdef_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT);
514     }
515     comdef_symbuf.reset();
516 
517     extdef = 0;
518 
519     if (indirectsymbuf1)
520         indirectsymbuf1.reset();
521     jumpTableSeg = 0;
522 
523     if (indirectsymbuf2)
524         indirectsymbuf2.reset();
525     pointersSeg = 0;
526 
527     // Initialize segments for CODE, DATA, UDATA and CDATA
528     size_t struct_section_size = I64 ? section_64.sizeof : section.sizeof;
529     if (SECbuf)
530     {
531         SECbuf.setsize(cast(uint)struct_section_size);
532     }
533     else
534     {
535         SECbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
536         if (!SECbuf)
537             err_nomem();
538         SECbuf.reserve(cast(uint)(SEC_TAB_INIT * struct_section_size));
539         // Ignore the first section - section numbers start at 1
540         SECbuf.writezeros(cast(uint)struct_section_size);
541     }
542     section_cnt = 1;
543 
544     SegData.reset();   // recycle memory
545     SegData.push();    // element 0 is reserved
546 
547     int align_ = I64 ? 4 : 2;            // align to 16 bytes for floating point
548     MachObj_getsegment("__text",  "__TEXT", 2, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS);
549     MachObj_getsegment("__data",  "__DATA", align_, S_REGULAR);     // DATA
550     MachObj_getsegment("__const", "__TEXT", 2, S_REGULAR);         // CDATA
551     MachObj_getsegment("__bss",   "__DATA", 4, S_ZEROFILL);        // UDATA
552     MachObj_getsegment("__const", "__DATA", align_, S_REGULAR);     // CDATAREL
553 
554     dwarf_initfile(filename);
555     return obj;
556 }
557 
558 /**************************
559  * Initialize the start of object output for this particular .o file.
560  *
561  * Input:
562  *      filename:       Name of source file
563  *      csegname:       User specified default code segment name
564  */
565 @trusted
566 void MachObj_initfile(const(char)* filename, const(char)* csegname, const(char)* modname)
567 {
568     //dbg_printf("MachObj_initfile(filename = %s, modname = %s)\n",filename,modname);
569     if (config.fulltypes)
570         dwarf_initmodule(filename, modname);
571 }
572 
573 /************************************
574  * Patch pseg/offset by adding in the vmaddr difference from
575  * pseg/offset to start of seg.
576  */
577 
578 @trusted
579 int32_t *patchAddr(int seg, targ_size_t offset)
580 {
581     return cast(int32_t *)(fobjbuf.buf + SecHdrTab[SegData[seg].SDshtidx].offset + offset);
582 }
583 
584 @trusted
585 int32_t *patchAddr64(int seg, targ_size_t offset)
586 {
587     return cast(int32_t *)(fobjbuf.buf + SecHdrTab64[SegData[seg].SDshtidx].offset + offset);
588 }
589 
590 @trusted
591 void patch(seg_data *pseg, targ_size_t offset, int seg, targ_size_t value)
592 {
593     //printf("patch(offset = x%04x, seg = %d, value = x%llx)\n", cast(uint)offset, seg, value);
594     if (I64)
595     {
596         int32_t *p = cast(int32_t *)(fobjbuf.buf + SecHdrTab64[pseg.SDshtidx].offset + offset);
597 static if (0)
598 {
599         printf("\taddr1 = x%llx\n\taddr2 = x%llx\n\t*p = x%llx\n\tdelta = x%llx\n",
600             SecHdrTab64[pseg.SDshtidx].addr,
601             SecHdrTab64[SegData[seg].SDshtidx].addr,
602             *p,
603             SecHdrTab64[SegData[seg].SDshtidx].addr -
604             (SecHdrTab64[pseg.SDshtidx].addr + offset));
605 }
606         *p += SecHdrTab64[SegData[seg].SDshtidx].addr -
607               (SecHdrTab64[pseg.SDshtidx].addr - value);
608     }
609     else
610     {
611         int32_t *p = cast(int32_t *)(fobjbuf.buf + SecHdrTab[pseg.SDshtidx].offset + offset);
612 static if (0)
613 {
614         printf("\taddr1 = x%x\n\taddr2 = x%x\n\t*p = x%x\n\tdelta = x%x\n",
615             SecHdrTab[pseg.SDshtidx].addr,
616             SecHdrTab[SegData[seg].SDshtidx].addr,
617             *p,
618             SecHdrTab[SegData[seg].SDshtidx].addr -
619             (SecHdrTab[pseg.SDshtidx].addr + offset));
620 }
621         *p += SecHdrTab[SegData[seg].SDshtidx].addr -
622               (SecHdrTab[pseg.SDshtidx].addr - value);
623     }
624 }
625 
626 /***************************
627  * Number symbols so they are
628  * ordered as locals, public and then extern/comdef
629  */
630 @trusted
631 void mach_numbersyms()
632 {
633     //printf("mach_numbersyms()\n");
634     int n = 0;
635 
636     int dim;
637     dim = cast(int)(local_symbuf.length() / (Symbol *).sizeof);
638     for (int i = 0; i < dim; i++)
639     {   Symbol *s = (cast(Symbol **)local_symbuf.buf)[i];
640         s.Sxtrnnum = n;
641         n++;
642     }
643 
644     dim = cast(int)(public_symbuf.length() / (Symbol *).sizeof);
645     for (int i = 0; i < dim; i++)
646     {   Symbol *s = (cast(Symbol **)public_symbuf.buf)[i];
647         s.Sxtrnnum = n;
648         n++;
649     }
650 
651     dim = cast(int)(extern_symbuf.length() / (Symbol *).sizeof);
652     for (int i = 0; i < dim; i++)
653     {   Symbol *s = (cast(Symbol **)extern_symbuf.buf)[i];
654         s.Sxtrnnum = n;
655         n++;
656     }
657 
658     dim = cast(int)(comdef_symbuf.length() / Comdef.sizeof);
659     for (int i = 0; i < dim; i++)
660     {   Comdef *c = (cast(Comdef *)comdef_symbuf.buf) + i;
661         c.sym.Sxtrnnum = n;
662         n++;
663     }
664 }
665 
666 
667 /***************************
668  * Fixup and terminate object file.
669  */
670 @trusted
671 void MachObj_termfile()
672 {
673     //dbg_printf("MachObj_termfile\n");
674     if (configv.addlinenumbers)
675     {
676         dwarf_termmodule();
677     }
678 }
679 
680 /*********************************
681  * Terminate package.
682  */
683 @trusted
684 void MachObj_term(const(char)* objfilename)
685 {
686     //printf("MachObj_term()\n");
687     outfixlist();           // backpatches
688 
689     if (configv.addlinenumbers)
690     {
691         dwarf_termfile();
692     }
693 
694 
695     /* Write out the object file in the following order:
696      *  header
697      *  commands
698      *          segment_command
699      *                  { sections }
700      *          symtab_command
701      *          dysymtab_command
702      *  { segment contents }
703      *  { relocations }
704      *  symbol table
705      *  string table
706      *  indirect symbol table
707      */
708 
709     uint foffset;
710     uint headersize;
711     uint sizeofcmds;
712 
713     // Write out the bytes for the header
714     if (I64)
715     {
716         mach_header_64 header = void;
717 
718         header.magic = MH_MAGIC_64;
719         header.cputype = CPU_TYPE_X86_64;
720         header.cpusubtype = CPU_SUBTYPE_I386_ALL;
721         header.filetype = MH_OBJECT;
722         header.ncmds = 3;
723         header.sizeofcmds = cast(uint)(segment_command_64.sizeof +
724                                 (section_cnt - 1) * section_64.sizeof +
725                             symtab_command.sizeof +
726                             dysymtab_command.sizeof);
727         header.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
728         header.reserved = 0;
729         fobjbuf.write(&header, header.sizeof);
730         foffset = header.sizeof;       // start after header
731         headersize = header.sizeof;
732         sizeofcmds = header.sizeofcmds;
733 
734         // Write the actual data later
735         fobjbuf.writezeros(header.sizeofcmds);
736         foffset += header.sizeofcmds;
737     }
738     else
739     {
740         mach_header header = void;
741 
742         header.magic = MH_MAGIC;
743         header.cputype = CPU_TYPE_I386;
744         header.cpusubtype = CPU_SUBTYPE_I386_ALL;
745         header.filetype = MH_OBJECT;
746         header.ncmds = 3;
747         header.sizeofcmds = cast(uint)(segment_command.sizeof +
748                                 (section_cnt - 1) * section.sizeof +
749                             symtab_command.sizeof +
750                             dysymtab_command.sizeof);
751         header.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
752         fobjbuf.write(&header, header.sizeof);
753         foffset = header.sizeof;       // start after header
754         headersize = header.sizeof;
755         sizeofcmds = header.sizeofcmds;
756 
757         // Write the actual data later
758         fobjbuf.writezeros(header.sizeofcmds);
759         foffset += header.sizeofcmds;
760     }
761 
762     segment_command segment_cmd = void;
763     segment_command_64 segment_cmd64 = void;
764     symtab_command symtab_cmd = void;
765     dysymtab_command dysymtab_cmd = void;
766 
767     memset(&segment_cmd, 0, segment_cmd.sizeof);
768     memset(&segment_cmd64, 0, segment_cmd64.sizeof);
769     memset(&symtab_cmd, 0, symtab_cmd.sizeof);
770     memset(&dysymtab_cmd, 0, dysymtab_cmd.sizeof);
771 
772     if (I64)
773     {
774         segment_cmd64.cmd = LC_SEGMENT_64;
775         segment_cmd64.cmdsize = cast(uint)(segment_cmd64.sizeof +
776                                     (section_cnt - 1) * section_64.sizeof);
777         segment_cmd64.nsects = section_cnt - 1;
778         segment_cmd64.maxprot = 7;
779         segment_cmd64.initprot = 7;
780     }
781     else
782     {
783         segment_cmd.cmd = LC_SEGMENT;
784         segment_cmd.cmdsize = cast(uint)(segment_cmd.sizeof +
785                                     (section_cnt - 1) * section.sizeof);
786         segment_cmd.nsects = section_cnt - 1;
787         segment_cmd.maxprot = 7;
788         segment_cmd.initprot = 7;
789     }
790 
791     symtab_cmd.cmd = LC_SYMTAB;
792     symtab_cmd.cmdsize = symtab_cmd.sizeof;
793 
794     dysymtab_cmd.cmd = LC_DYSYMTAB;
795     dysymtab_cmd.cmdsize = dysymtab_cmd.sizeof;
796 
797     /* If a __pointers section was emitted, need to set the .reserved1
798      * field to the symbol index in the indirect symbol table of the
799      * start of the __pointers symbols.
800      */
801     if (pointersSeg)
802     {
803         seg_data *pseg = SegData[pointersSeg];
804         if (I64)
805         {
806             section_64 *psechdr = &SecHdrTab64[pseg.SDshtidx]; // corresponding section
807             psechdr.reserved1 = cast(uint)(indirectsymbuf1
808                 ? indirectsymbuf1.length() / (Symbol *).sizeof
809                 : 0);
810         }
811         else
812         {
813             section *psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section
814             psechdr.reserved1 = cast(uint)(indirectsymbuf1
815                 ? indirectsymbuf1.length() / (Symbol *).sizeof
816                 : 0);
817         }
818     }
819 
820     // Walk through sections determining size and file offsets
821 
822     //
823     // First output individual section data associate with program
824     //  code and data
825     //
826     foffset = elf_align(I64 ? 8 : 4, foffset);
827     if (I64)
828         segment_cmd64.fileoff = foffset;
829     else
830         segment_cmd.fileoff = foffset;
831     uint vmaddr = 0;
832 
833     //printf("Setup offsets and sizes foffset %d\n\tsection_cnt %d, SegData.length %d\n",foffset,section_cnt,SegData.length);
834     // Zero filled segments go at the end, so go through segments twice
835     for (int i = 0; i < 2; i++)
836     {
837         for (int seg = 1; seg < SegData.length; seg++)
838         {
839             seg_data *pseg = SegData[seg];
840             if (I64)
841             {
842                 section_64 *psechdr = &SecHdrTab64[pseg.SDshtidx]; // corresponding section
843 
844                 // Do zero-fill the second time through this loop
845                 if (i ^ (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL))
846                     continue;
847 
848                 int align_ = 1 << psechdr._align;
849                 while (psechdr._align > 0 && align_ < pseg.SDalignment)
850                 {
851                     psechdr._align += 1;
852                     align_ <<= 1;
853                 }
854                 foffset = elf_align(align_, foffset);
855                 vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1);
856                 if (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL)
857                 {
858                     psechdr.offset = 0;
859                     psechdr.size = pseg.SDoffset; // accumulated size
860                 }
861                 else
862                 {
863                     psechdr.offset = foffset;
864                     psechdr.size = 0;
865                     //printf("\tsection name %s,", psechdr.sectname);
866                     if (pseg.SDbuf && pseg.SDbuf.length())
867                     {
868                         //printf("\tsize %d\n", pseg.SDbuf.length());
869                         psechdr.size = pseg.SDbuf.length();
870                         fobjbuf.write(pseg.SDbuf.buf, cast(uint)psechdr.size);
871                         foffset += psechdr.size;
872                     }
873                 }
874                 psechdr.addr = vmaddr;
875                 vmaddr += psechdr.size;
876                 //printf(" assigned offset %d, size %d\n", foffset, psechdr.sh_size);
877             }
878             else
879             {
880                 section *psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section
881 
882                 // Do zero-fill the second time through this loop
883                 if (i ^ (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL))
884                     continue;
885 
886                 int align_ = 1 << psechdr._align;
887                 while (psechdr._align > 0 && align_ < pseg.SDalignment)
888                 {
889                     psechdr._align += 1;
890                     align_ <<= 1;
891                 }
892                 foffset = elf_align(align_, foffset);
893                 vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1);
894                 if (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL)
895                 {
896                     psechdr.offset = 0;
897                     psechdr.size = cast(uint)pseg.SDoffset; // accumulated size
898                 }
899                 else
900                 {
901                     psechdr.offset = foffset;
902                     psechdr.size = 0;
903                     //printf("\tsection name %s,", psechdr.sectname);
904                     if (pseg.SDbuf && pseg.SDbuf.length())
905                     {
906                         //printf("\tsize %d\n", pseg.SDbuf.length());
907                         psechdr.size = cast(uint)pseg.SDbuf.length();
908                         fobjbuf.write(pseg.SDbuf.buf, psechdr.size);
909                         foffset += psechdr.size;
910                     }
911                 }
912                 psechdr.addr = vmaddr;
913                 vmaddr += psechdr.size;
914                 //printf(" assigned offset %d, size %d\n", foffset, psechdr.sh_size);
915             }
916         }
917     }
918 
919     if (I64)
920     {
921         segment_cmd64.vmsize = vmaddr;
922         segment_cmd64.filesize = foffset - segment_cmd64.fileoff;
923         /* Bugzilla 5331: Apparently having the filesize field greater than the vmsize field is an
924          * error, and is happening sometimes.
925          */
926         if (segment_cmd64.filesize > vmaddr)
927             segment_cmd64.vmsize = segment_cmd64.filesize;
928     }
929     else
930     {
931         segment_cmd.vmsize = vmaddr;
932         segment_cmd.filesize = foffset - segment_cmd.fileoff;
933         /* Bugzilla 5331: Apparently having the filesize field greater than the vmsize field is an
934          * error, and is happening sometimes.
935          */
936         if (segment_cmd.filesize > vmaddr)
937             segment_cmd.vmsize = segment_cmd.filesize;
938     }
939 
940     // Put out relocation data
941     mach_numbersyms();
942     for (int seg = 1; seg < SegData.length; seg++)
943     {
944         seg_data *pseg = SegData[seg];
945         section *psechdr = null;
946         section_64 *psechdr64 = null;
947         if (I64)
948         {
949             psechdr64 = &SecHdrTab64[pseg.SDshtidx];   // corresponding section
950             //printf("psechdr.addr = x%llx\n", psechdr64.addr);
951         }
952         else
953         {
954             psechdr = &SecHdrTab[pseg.SDshtidx];   // corresponding section
955             //printf("psechdr.addr = x%x\n", psechdr.addr);
956         }
957         foffset = elf_align(I64 ? 8 : 4, foffset);
958         uint reloff = foffset;
959         uint nreloc = 0;
960         if (pseg.SDrel)
961         {   Relocation *r = cast(Relocation *)pseg.SDrel.buf;
962             Relocation *rend = cast(Relocation *)(pseg.SDrel.buf + pseg.SDrel.length());
963             for (; r != rend; r++)
964             {   Symbol *s = r.targsym;
965                 const(char)* rs = r.rtype == RELaddr ? "addr" : "rel";
966                 //printf("%d:x%04llx : tseg %d tsym %s REL%s\n", seg, r.offset, r.targseg, s ? s.Sident.ptr : "0", rs);
967                 relocation_info rel;
968                 scattered_relocation_info srel;
969                 if (s)
970                 {
971                     //printf("Relocation\n");
972                     //symbol_print(s);
973                     if (r.flag == 1)  // emit SUBTRACTOR/UNSIGNED pair
974                     {
975                         if (I64)
976                         {
977                             rel.r_type = X86_64_RELOC_SUBTRACTOR;
978                             rel.r_address = cast(int)r.offset;
979                             rel.r_symbolnum = r.funcsym.Sxtrnnum;
980                             rel.r_pcrel = 0;
981                             rel.r_length = 3;
982                             rel.r_extern = 1;
983                             fobjbuf.write(&rel, rel.sizeof);
984                             foffset += (rel).sizeof;
985                             ++nreloc;
986 
987                             rel.r_type = X86_64_RELOC_UNSIGNED;
988                             rel.r_symbolnum = s.Sxtrnnum;
989                             fobjbuf.write(&rel, rel.sizeof);
990                             foffset += rel.sizeof;
991                             ++nreloc;
992 
993                             // patch with fdesym.Soffset - offset
994                             long *p = cast(long *)patchAddr64(seg, r.offset);
995                             *p += r.funcsym.Soffset - r.offset;
996                             continue;
997                         }
998                         else
999                         {
1000                             // address = segment + offset
1001                             int targ_address = cast(int)(SecHdrTab[SegData[s.Sseg].SDshtidx].addr + s.Soffset);
1002                             int fixup_address = cast(int)(psechdr.addr + r.offset);
1003 
1004                             srel.r_scattered = 1;
1005                             srel.r_type = GENERIC_RELOC_LOCAL_SECTDIFF;
1006                             srel.r_address = cast(uint)r.offset;
1007                             srel.r_pcrel = 0;
1008                             srel.r_length = 2;
1009                             srel.r_value = targ_address;
1010                             fobjbuf.write((&srel)[0 .. 1]);
1011                             foffset += srel.sizeof;
1012                             ++nreloc;
1013 
1014                             srel.r_type = GENERIC_RELOC_PAIR;
1015                             srel.r_address = 0;
1016                             srel.r_value = fixup_address;
1017                             fobjbuf.write(&srel, srel.sizeof);
1018                             foffset += srel.sizeof;
1019                             ++nreloc;
1020 
1021                             int32_t *p = patchAddr(seg, r.offset);
1022                             *p += targ_address - fixup_address;
1023                             continue;
1024                         }
1025                     }
1026                     else if (pseg.isCode())
1027                     {
1028                         if (I64)
1029                         {
1030                             rel.r_type = (r.rtype == RELrel)
1031                                     ? X86_64_RELOC_BRANCH
1032                                     : X86_64_RELOC_SIGNED;
1033                             if (r.val == -1)
1034                                 rel.r_type = X86_64_RELOC_SIGNED_1;
1035                             else if (r.val == -2)
1036                                 rel.r_type = X86_64_RELOC_SIGNED_2;
1037                             if (r.val == -4)
1038                                 rel.r_type = X86_64_RELOC_SIGNED_4;
1039 
1040                             if (s.Sclass == SC.extern_ ||
1041                                 s.Sclass == SC.comdef  ||
1042                                 s.Sclass == SC.comdat  ||
1043                                 s.Sclass == SC.static_ ||
1044                                 s.Sclass == SC.global)
1045                             {
1046                                 if ((s.ty() & mTYLINK) == mTYthread && r.rtype == RELaddr)
1047                                     rel.r_type = X86_64_RELOC_TLV;
1048                                 else if (s.Sfl == FLfunc && s.Sclass == SC.static_ && r.rtype == RELaddr)
1049                                     rel.r_type = X86_64_RELOC_SIGNED;
1050                                 else if ((s.Sfl == FLfunc || s.Sfl == FLextern || s.Sclass == SC.global ||
1051                                           s.Sclass == SC.comdat || s.Sclass == SC.comdef) && r.rtype == RELaddr)
1052                                 {
1053                                     rel.r_type = X86_64_RELOC_GOT_LOAD;
1054                                     if (seg == eh_frame_seg ||
1055                                         seg == except_table_seg)
1056                                         rel.r_type = X86_64_RELOC_GOT;
1057                                 }
1058                                 rel.r_address = cast(int)r.offset;
1059                                 rel.r_symbolnum = s.Sxtrnnum;
1060                                 rel.r_pcrel = 1;
1061                                 rel.r_length = 2;
1062                                 rel.r_extern = 1;
1063                                 fobjbuf.write(&rel, rel.sizeof);
1064                                 foffset += rel.sizeof;
1065                                 nreloc++;
1066                                 continue;
1067                             }
1068                             else
1069                             {
1070                                 rel.r_address = cast(int)r.offset;
1071                                 rel.r_symbolnum = s.Sseg;
1072                                 rel.r_pcrel = 1;
1073                                 rel.r_length = 2;
1074                                 rel.r_extern = 0;
1075                                 fobjbuf.write(&rel, rel.sizeof);
1076                                 foffset += rel.sizeof;
1077                                 nreloc++;
1078 
1079                                 int32_t *p = patchAddr64(seg, r.offset);
1080                                 // Absolute address; add in addr of start of targ seg
1081 //printf("*p = x%x, .addr = x%x, Soffset = x%x\n", *p, cast(int)SecHdrTab64[SegData[s.Sseg].SDshtidx].addr, cast(int)s.Soffset);
1082 //printf("pseg = x%x, r.offset = x%x\n", cast(int)SecHdrTab64[pseg.SDshtidx].addr, cast(int)r.offset);
1083                                 *p += SecHdrTab64[SegData[s.Sseg].SDshtidx].addr;
1084                                 *p += s.Soffset;
1085                                 *p -= SecHdrTab64[pseg.SDshtidx].addr + r.offset + 4;
1086                                 //patch(pseg, r.offset, s.Sseg, s.Soffset);
1087                                 continue;
1088                             }
1089                         }
1090                     }
1091                     else
1092                     {
1093                         if (s.Sclass == SC.extern_ ||
1094                             s.Sclass == SC.comdef ||
1095                             s.Sclass == SC.comdat)
1096                         {
1097                             rel.r_address = cast(int)r.offset;
1098                             rel.r_symbolnum = s.Sxtrnnum;
1099                             rel.r_pcrel = 0;
1100                             rel.r_length = 2;
1101                             rel.r_extern = 1;
1102                             rel.r_type = GENERIC_RELOC_VANILLA;
1103                             if (I64)
1104                             {
1105                                 rel.r_type = X86_64_RELOC_UNSIGNED;
1106                                 rel.r_length = 3;
1107                             }
1108                             fobjbuf.write(&rel, rel.sizeof);
1109                             foffset += rel.sizeof;
1110                             nreloc++;
1111                             continue;
1112                         }
1113                         else
1114                         {
1115                             rel.r_address = cast(int)r.offset;
1116                             rel.r_symbolnum = s.Sseg;
1117                             rel.r_pcrel = 0;
1118                             rel.r_length = 2;
1119                             rel.r_extern = 0;
1120                             rel.r_type = GENERIC_RELOC_VANILLA;
1121                             if (I64)
1122                             {
1123                                 rel.r_type = X86_64_RELOC_UNSIGNED;
1124                                 rel.r_length = 3;
1125                                 if (0 && s.Sseg != seg)
1126                                     rel.r_type = X86_64_RELOC_BRANCH;
1127                             }
1128                             fobjbuf.write(&rel, rel.sizeof);
1129                             foffset += rel.sizeof;
1130                             nreloc++;
1131                             if (I64)
1132                             {
1133                                 rel.r_length = 3;
1134                                 int32_t *p = patchAddr64(seg, r.offset);
1135                                 // Absolute address; add in addr of start of targ seg
1136                                 *p += SecHdrTab64[SegData[s.Sseg].SDshtidx].addr + s.Soffset;
1137                                 //patch(pseg, r.offset, s.Sseg, s.Soffset);
1138                             }
1139                             else
1140                             {
1141                                 int32_t *p = patchAddr(seg, r.offset);
1142                                 // Absolute address; add in addr of start of targ seg
1143                                 *p += SecHdrTab[SegData[s.Sseg].SDshtidx].addr + s.Soffset;
1144                                 //patch(pseg, r.offset, s.Sseg, s.Soffset);
1145                             }
1146                             continue;
1147                         }
1148                     }
1149                 }
1150                 else if (r.rtype == RELaddr && pseg.isCode())
1151                 {
1152                     srel.r_scattered = 1;
1153 
1154                     srel.r_address = cast(uint)r.offset;
1155                     srel.r_length = 2;
1156                     if (I64)
1157                     {
1158                         int32_t *p64 = patchAddr64(seg, r.offset);
1159                         srel.r_type = X86_64_RELOC_GOT;
1160                         srel.r_value = cast(int)(SecHdrTab64[SegData[r.targseg].SDshtidx].addr + *p64);
1161                         //printf("SECTDIFF: x%llx + x%llx = x%x\n", SecHdrTab[SegData[r.targseg].SDshtidx].addr, *p, srel.r_value);
1162                     }
1163                     else
1164                     {
1165                         int32_t *p = patchAddr(seg, r.offset);
1166                         srel.r_type = GENERIC_RELOC_LOCAL_SECTDIFF;
1167                         srel.r_value = SecHdrTab[SegData[r.targseg].SDshtidx].addr + *p;
1168                         //printf("SECTDIFF: x%x + x%x = x%x\n", SecHdrTab[SegData[r.targseg].SDshtidx].addr, *p, srel.r_value);
1169                     }
1170                     srel.r_pcrel = 0;
1171                     fobjbuf.write(&srel, srel.sizeof);
1172                     foffset += srel.sizeof;
1173                     nreloc++;
1174 
1175                     srel.r_address = 0;
1176                     srel.r_length = 2;
1177                     if (I64)
1178                     {
1179                         srel.r_type = X86_64_RELOC_SIGNED;
1180                         srel.r_value = cast(int)(SecHdrTab64[pseg.SDshtidx].addr +
1181                                 r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1182                     }
1183                     else
1184                     {
1185                         srel.r_type = GENERIC_RELOC_PAIR;
1186                         if (r.funcsym)
1187                             srel.r_value = cast(int)(SecHdrTab[pseg.SDshtidx].addr +
1188                                     r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1189                         else
1190                             srel.r_value = cast(int)(psechdr.addr + r.offset);
1191                         //printf("srel.r_value = x%x, psechdr.addr = x%x, r.offset = x%x\n",
1192                             //cast(int)srel.r_value, cast(int)psechdr.addr, cast(int)r.offset);
1193                     }
1194                     srel.r_pcrel = 0;
1195                     fobjbuf.write(&srel, srel.sizeof);
1196                     foffset += srel.sizeof;
1197                     nreloc++;
1198 
1199                     // Recalc due to possible realloc of fobjbuf.buf
1200                     if (I64)
1201                     {
1202                         int32_t *p64 = patchAddr64(seg, r.offset);
1203                         //printf("address = x%x, p64 = %p *p64 = x%llx\n", r.offset, p64, *p64);
1204                         *p64 += SecHdrTab64[SegData[r.targseg].SDshtidx].addr -
1205                               (SecHdrTab64[pseg.SDshtidx].addr + r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1206                     }
1207                     else
1208                     {
1209                         int32_t *p = patchAddr(seg, r.offset);
1210                         //printf("address = x%x, p = %p *p = x%x\n", r.offset, p, *p);
1211                         if (r.funcsym)
1212                             *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr -
1213                                   (SecHdrTab[pseg.SDshtidx].addr + r.funcsym.Slocalgotoffset + _tysize[TYnptr]);
1214                         else
1215                             // targ_address - fixup_address
1216                             *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr -
1217                                   (psechdr.addr + r.offset);
1218                     }
1219                     continue;
1220                 }
1221                 else
1222                 {
1223                     rel.r_address = cast(int)r.offset;
1224                     rel.r_symbolnum = r.targseg;
1225                     rel.r_pcrel = (r.rtype == RELaddr) ? 0 : 1;
1226                     rel.r_length = 2;
1227                     rel.r_extern = 0;
1228                     rel.r_type = GENERIC_RELOC_VANILLA;
1229                     if (I64)
1230                     {
1231                         rel.r_type = X86_64_RELOC_UNSIGNED;
1232                         rel.r_length = 3;
1233                         if (0 && r.targseg != seg)
1234                             rel.r_type = X86_64_RELOC_BRANCH;
1235                     }
1236                     fobjbuf.write(&rel, rel.sizeof);
1237                     foffset += rel.sizeof;
1238                     nreloc++;
1239                     if (I64)
1240                     {
1241                         int32_t *p64 = patchAddr64(seg, r.offset);
1242                         //long before = *p64;
1243                         if (rel.r_pcrel)
1244                             // Relative address
1245                             patch(pseg, r.offset, r.targseg, 0);
1246                         else
1247                         {   // Absolute address; add in addr of start of targ seg
1248 //printf("*p = x%x, targ.addr = x%x\n", *p64, cast(int)SecHdrTab64[SegData[r.targseg].SDshtidx].addr);
1249 //printf("pseg = x%x, r.offset = x%x\n", cast(int)SecHdrTab64[pseg.SDshtidx].addr, cast(int)r.offset);
1250                             *p64 += SecHdrTab64[SegData[r.targseg].SDshtidx].addr;
1251                             //*p64 -= SecHdrTab64[pseg.SDshtidx].addr;
1252                         }
1253                         //printf("%d:x%04x before = x%04llx, after = x%04llx pcrel = %d\n", seg, r.offset, before, *p64, rel.r_pcrel);
1254                     }
1255                     else
1256                     {
1257                         int32_t *p = patchAddr(seg, r.offset);
1258                         //int32_t before = *p;
1259                         if (rel.r_pcrel)
1260                             // Relative address
1261                             patch(pseg, r.offset, r.targseg, 0);
1262                         else
1263                             // Absolute address; add in addr of start of targ seg
1264                             *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr;
1265                         //printf("%d:x%04x before = x%04x, after = x%04x pcrel = %d\n", seg, r.offset, before, *p, rel.r_pcrel);
1266                     }
1267                     continue;
1268                 }
1269             }
1270         }
1271         if (nreloc)
1272         {
1273             if (I64)
1274             {
1275                 psechdr64.reloff = reloff;
1276                 psechdr64.nreloc = nreloc;
1277             }
1278             else
1279             {
1280                 psechdr.reloff = reloff;
1281                 psechdr.nreloc = nreloc;
1282             }
1283         }
1284     }
1285 
1286     // Put out symbol table
1287     foffset = elf_align(I64 ? 8 : 4, foffset);
1288     symtab_cmd.symoff = foffset;
1289     dysymtab_cmd.ilocalsym = 0;
1290     dysymtab_cmd.nlocalsym  = cast(uint)(local_symbuf.length() / (Symbol *).sizeof);
1291     dysymtab_cmd.iextdefsym = dysymtab_cmd.nlocalsym;
1292     dysymtab_cmd.nextdefsym = cast(uint)(public_symbuf.length() / (Symbol *).sizeof);
1293     dysymtab_cmd.iundefsym = dysymtab_cmd.iextdefsym + dysymtab_cmd.nextdefsym;
1294     int nexterns = cast(int)(extern_symbuf.length() / (Symbol *).sizeof);
1295     int ncomdefs = cast(int)(comdef_symbuf.length() / Comdef.sizeof);
1296     dysymtab_cmd.nundefsym  = nexterns + ncomdefs;
1297     symtab_cmd.nsyms =  dysymtab_cmd.nlocalsym +
1298                         dysymtab_cmd.nextdefsym +
1299                         dysymtab_cmd.nundefsym;
1300     fobjbuf.reserve(cast(uint)(symtab_cmd.nsyms * (I64 ? nlist_64.sizeof : nlist.sizeof)));
1301     for (int i = 0; i < dysymtab_cmd.nlocalsym; i++)
1302     {   Symbol *s = (cast(Symbol **)local_symbuf.buf)[i];
1303         nlist_64 sym = void;
1304         sym.n_strx = mach_addmangled(s);
1305         sym.n_type = N_SECT;
1306         sym.n_desc = 0;
1307         if (s.Sclass == SC.comdat)
1308             sym.n_desc = N_WEAK_DEF;
1309         sym.n_sect = cast(ubyte)s.Sseg;
1310         if (I64)
1311         {
1312             sym.n_value = s.Soffset + SecHdrTab64[SegData[s.Sseg].SDshtidx].addr;
1313             fobjbuf.write(&sym, sym.sizeof);
1314         }
1315         else
1316         {
1317             nlist sym32 = void;
1318             sym32.n_strx = sym.n_strx;
1319             sym32.n_value = cast(uint)(s.Soffset + SecHdrTab[SegData[s.Sseg].SDshtidx].addr);
1320             sym32.n_type = sym.n_type;
1321             sym32.n_desc = sym.n_desc;
1322             sym32.n_sect = sym.n_sect;
1323             fobjbuf.write(&sym32, sym32.sizeof);
1324         }
1325     }
1326     for (int i = 0; i < dysymtab_cmd.nextdefsym; i++)
1327     {   Symbol *s = (cast(Symbol **)public_symbuf.buf)[i];
1328 
1329         //printf("Writing public symbol %d:x%x %s\n", s.Sseg, s.Soffset, s.Sident);
1330         nlist_64 sym = void;
1331         sym.n_strx = mach_addmangled(s);
1332         sym.n_type = N_EXT | N_SECT;
1333         if (s.Sflags & SFLhidden)
1334             sym.n_type |= N_PEXT; // private extern
1335         sym.n_desc = 0;
1336         if (s.Sclass == SC.comdat)
1337             sym.n_desc = N_WEAK_DEF;
1338         sym.n_sect = cast(ubyte)s.Sseg;
1339         if (I64)
1340         {
1341             sym.n_value = s.Soffset + SecHdrTab64[SegData[s.Sseg].SDshtidx].addr;
1342             fobjbuf.write(&sym, sym.sizeof);
1343         }
1344         else
1345         {
1346             nlist sym32 = void;
1347             sym32.n_strx = sym.n_strx;
1348             sym32.n_value = cast(uint)(s.Soffset + SecHdrTab[SegData[s.Sseg].SDshtidx].addr);
1349             sym32.n_type = sym.n_type;
1350             sym32.n_desc = sym.n_desc;
1351             sym32.n_sect = sym.n_sect;
1352             fobjbuf.write(&sym32, sym32.sizeof);
1353         }
1354     }
1355     for (int i = 0; i < nexterns; i++)
1356     {   Symbol *s = (cast(Symbol **)extern_symbuf.buf)[i];
1357         nlist_64 sym = void;
1358         sym.n_strx = mach_addmangled(s);
1359         sym.n_value = s.Soffset;
1360         sym.n_type = N_EXT | N_UNDF;
1361         sym.n_desc = tyfunc(s.ty()) ? REFERENCE_FLAG_UNDEFINED_LAZY
1362                                      : REFERENCE_FLAG_UNDEFINED_NON_LAZY;
1363         sym.n_sect = 0;
1364         if (I64)
1365             fobjbuf.write(&sym, sym.sizeof);
1366         else
1367         {
1368             nlist sym32 = void;
1369             sym32.n_strx = sym.n_strx;
1370             sym32.n_value = cast(uint)sym.n_value;
1371             sym32.n_type = sym.n_type;
1372             sym32.n_desc = sym.n_desc;
1373             sym32.n_sect = sym.n_sect;
1374             fobjbuf.write(&sym32, sym32.sizeof);
1375         }
1376     }
1377     for (int i = 0; i < ncomdefs; i++)
1378     {   Comdef *c = (cast(Comdef *)comdef_symbuf.buf) + i;
1379         nlist_64 sym = void;
1380         sym.n_strx = mach_addmangled(c.sym);
1381         sym.n_value = c.size * c.count;
1382         sym.n_type = N_EXT | N_UNDF;
1383         int align_;
1384         if (c.size < 2)
1385             align_ = 0;          // align_ is expressed as power of 2
1386         else if (c.size < 4)
1387             align_ = 1;
1388         else if (c.size < 8)
1389             align_ = 2;
1390         else if (c.size < 16)
1391             align_ = 3;
1392         else
1393             align_ = 4;
1394         sym.n_desc = cast(ushort)(align_ << 8);
1395         sym.n_sect = 0;
1396         if (I64)
1397             fobjbuf.write(&sym, sym.sizeof);
1398         else
1399         {
1400             nlist sym32 = void;
1401             sym32.n_strx = sym.n_strx;
1402             sym32.n_value = cast(uint)sym.n_value;
1403             sym32.n_type = sym.n_type;
1404             sym32.n_desc = sym.n_desc;
1405             sym32.n_sect = sym.n_sect;
1406             fobjbuf.write(&sym32, sym32.sizeof);
1407         }
1408     }
1409     if (extdef)
1410     {
1411         nlist_64 sym = void;
1412         sym.n_strx = extdef;
1413         sym.n_value = 0;
1414         sym.n_type = N_EXT | N_UNDF;
1415         sym.n_desc = 0;
1416         sym.n_sect = 0;
1417         if (I64)
1418             fobjbuf.write(&sym, sym.sizeof);
1419         else
1420         {
1421             nlist sym32 = void;
1422             sym32.n_strx = sym.n_strx;
1423             sym32.n_value = cast(uint)sym.n_value;
1424             sym32.n_type = sym.n_type;
1425             sym32.n_desc = sym.n_desc;
1426             sym32.n_sect = sym.n_sect;
1427             fobjbuf.write(&sym32, sym32.sizeof);
1428         }
1429         symtab_cmd.nsyms++;
1430     }
1431     foffset += symtab_cmd.nsyms * (I64 ? nlist_64.sizeof : nlist.sizeof);
1432 
1433     // Put out string table
1434     foffset = elf_align(I64 ? 8 : 4, foffset);
1435     symtab_cmd.stroff = foffset;
1436     symtab_cmd.strsize = cast(uint)symtab_strings.length();
1437     fobjbuf.write(symtab_strings.buf, symtab_cmd.strsize);
1438     foffset += symtab_cmd.strsize;
1439 
1440     // Put out indirectsym table, which is in two parts
1441     foffset = elf_align(I64 ? 8 : 4, foffset);
1442     dysymtab_cmd.indirectsymoff = foffset;
1443     if (indirectsymbuf1)
1444     {
1445         dysymtab_cmd.nindirectsyms += indirectsymbuf1.length() / (Symbol *).sizeof;
1446         for (int i = 0; i < dysymtab_cmd.nindirectsyms; i++)
1447         {   Symbol *s = (cast(Symbol **)indirectsymbuf1.buf)[i];
1448             fobjbuf.write32(s.Sxtrnnum);
1449         }
1450     }
1451     if (indirectsymbuf2)
1452     {
1453         int n = cast(int)(indirectsymbuf2.length() / (Symbol *).sizeof);
1454         dysymtab_cmd.nindirectsyms += n;
1455         for (int i = 0; i < n; i++)
1456         {   Symbol *s = (cast(Symbol **)indirectsymbuf2.buf)[i];
1457             fobjbuf.write32(s.Sxtrnnum);
1458         }
1459     }
1460     foffset += dysymtab_cmd.nindirectsyms * 4;
1461 
1462     /* The correct offsets are now determined, so
1463      * rewind and fix the header.
1464      */
1465     fobjbuf.position(headersize, sizeofcmds);
1466     if (I64)
1467     {
1468         fobjbuf.write(&segment_cmd64, segment_cmd64.sizeof);
1469         fobjbuf.write(SECbuf.buf + section_64.sizeof, cast(uint)((section_cnt - 1) * section_64.sizeof));
1470     }
1471     else
1472     {
1473         fobjbuf.write(&segment_cmd, segment_cmd.sizeof);
1474         fobjbuf.write(SECbuf.buf + section.sizeof, cast(uint)((section_cnt - 1) * section.sizeof));
1475     }
1476     fobjbuf.write(&symtab_cmd, symtab_cmd.sizeof);
1477     fobjbuf.write(&dysymtab_cmd, dysymtab_cmd.sizeof);
1478     fobjbuf.position(foffset, 0);
1479 }
1480 
1481 /*****************************
1482  * Line number support.
1483  */
1484 
1485 /***************************
1486  * Record file and line number at segment and offset.
1487  * The actual .debug_line segment is put out by dwarf_termfile().
1488  * Params:
1489  *      srcpos = source file position
1490  *      seg = segment it corresponds to
1491  *      offset = offset within seg
1492  */
1493 @trusted
1494 void MachObj_linnum(Srcpos srcpos, int seg, targ_size_t offset)
1495 {
1496     if (srcpos.Slinnum == 0)
1497         return;
1498 
1499 static if (0)
1500 {
1501     printf("MachObj_linnum(seg=%d, offset=x%lx) ", seg, offset);
1502     srcpos.print("");
1503 }
1504 
1505     if (!srcpos.Sfilename)
1506         return;
1507 
1508     size_t i;
1509     seg_data *pseg = SegData[seg];
1510 
1511     // Find entry i in SDlinnum_data[] that corresponds to srcpos filename
1512     for (i = 0; 1; i++)
1513     {
1514         if (i == pseg.SDlinnum_data.length)
1515         {   // Create new entry
1516             pseg.SDlinnum_data.push(linnum_data(srcpos.Sfilename));
1517             break;
1518         }
1519         if (pseg.SDlinnum_data[i].filename == srcpos.Sfilename)
1520             break;
1521     }
1522 
1523     linnum_data *ld = &pseg.SDlinnum_data[i];
1524 //    printf("i = %d, ld = x%x\n", i, ld);
1525     ld.linoff.push(LinOff(srcpos.Slinnum, cast(uint)offset));
1526 }
1527 
1528 
1529 /*******************************
1530  * Set start address
1531  */
1532 
1533 void MachObj_startaddress(Symbol *s)
1534 {
1535     //dbg_printf("MachObj_startaddress(Symbol *%s)\n",s.Sident);
1536     //obj.startaddress = s;
1537 }
1538 
1539 /*******************************
1540  * Output library name.
1541  */
1542 
1543 bool MachObj_includelib(scope const char[] name)
1544 {
1545     //dbg_printf("MachObj_includelibx(name *%s)\n",name);
1546     return false;
1547 }
1548 
1549 /*******************************
1550 * Output linker directive.
1551 */
1552 
1553 bool MachObj_linkerdirective(const(char)* name)
1554 {
1555     return false;
1556 }
1557 
1558 /**********************************
1559  * Do we allow zero sized objects?
1560  */
1561 
1562 bool MachObj_allowZeroSize()
1563 {
1564     return true;
1565 }
1566 
1567 /**************************
1568  * Embed string in executable.
1569  */
1570 
1571 void MachObj_exestr(const(char)* p)
1572 {
1573     //dbg_printf("MachObj_exestr(char *%s)\n",p);
1574 }
1575 
1576 /**************************
1577  * Embed string in obj.
1578  */
1579 
1580 void MachObj_user(const(char)* p)
1581 {
1582     //dbg_printf("MachObj_user(char *%s)\n",p);
1583 }
1584 
1585 /*******************************
1586  * Output a weak extern record.
1587  */
1588 
1589 void MachObj_wkext(Symbol *s1,Symbol *s2)
1590 {
1591     //dbg_printf("MachObj_wkext(Symbol *%s,Symbol *s2)\n",s1.Sident.ptr,s2.Sident.ptr);
1592 }
1593 
1594 /*******************************
1595  * Output file name record.
1596  *
1597  * Currently assumes that obj_filename will not be called
1598  *      twice for the same file.
1599  */
1600 
1601 void MachObj_filename(const(char)* modname)
1602 {
1603     //dbg_printf("MachObj_filename(char *%s)\n",modname);
1604     // Not supported by Mach-O
1605 }
1606 
1607 /*******************************
1608  * Embed compiler version in .obj file.
1609  */
1610 
1611 void MachObj_compiler(const(char)* p)
1612 {
1613     //dbg_printf("MachObj_compiler\n");
1614     MachObj_user(p);
1615 }
1616 
1617 
1618 /**************************************
1619  * Symbol is the function that calls the static constructors.
1620  * Put a pointer to it into a special segment that the startup code
1621  * looks at.
1622  * Input:
1623  *      s       static constructor function
1624  *      dtor    !=0 if leave space for static destructor
1625  *      seg     1:      user
1626  *              2:      lib
1627  *              3:      compiler
1628  */
1629 
1630 void MachObj_staticctor(Symbol *s, int, int)
1631 {
1632     MachObj_setModuleCtorDtor(s, true);
1633 }
1634 
1635 /**************************************
1636  * Symbol is the function that calls the static destructors.
1637  * Put a pointer to it into a special segment that the exit code
1638  * looks at.
1639  * Input:
1640  *      s       static destructor function
1641  */
1642 
1643 void MachObj_staticdtor(Symbol *s)
1644 {
1645     MachObj_setModuleCtorDtor(s, false);
1646 }
1647 
1648 
1649 /***************************************
1650  * Stuff pointer to function in its own segment.
1651  * Used for static ctor and dtor lists.
1652  */
1653 @trusted
1654 void MachObj_setModuleCtorDtor(Symbol *sfunc, bool isCtor)
1655 {
1656     const align_ = I64 ? 3 : 2; // align to _tysize[TYnptr]
1657 
1658     IDXSEC seg = isCtor
1659                 ? getsegment2(seg_mod_init_func, "__mod_init_func", "__DATA", align_, S_MOD_INIT_FUNC_POINTERS)
1660                 : getsegment2(seg_mod_term_func, "__mod_term_func", "__DATA", align_, S_MOD_TERM_FUNC_POINTERS);
1661 
1662     const int relflags = I64 ? CFoff | CFoffset64 : CFoff;
1663     const int sz = MachObj_reftoident(seg, SegData[seg].SDoffset, sfunc, 0, relflags);
1664     SegData[seg].SDoffset += sz;
1665 }
1666 
1667 
1668 /***************************************
1669  * Stuff the following data (instance of struct FuncTable) in a separate segment:
1670  *      pointer to function
1671  *      pointer to ehsym
1672  *      length of function
1673  */
1674 @trusted
1675 void MachObj_ehtables(Symbol *sfunc,uint size,Symbol *ehsym)
1676 {
1677     //dbg_printf("MachObj_ehtables(%s) \n",sfunc.Sident.ptr);
1678 
1679     /* BUG: this should go into a COMDAT if sfunc is in a COMDAT
1680      * otherwise the duplicates aren't removed.
1681      */
1682 
1683     int align_ = I64 ? 3 : 2;            // align to _tysize[TYnptr]
1684     // The size is (FuncTable).sizeof in deh2.d
1685     int seg = getsegment2(seg_deh_eh, "__deh_eh", "__DATA", align_, S_REGULAR);
1686 
1687     OutBuffer *buf = SegData[seg].SDbuf;
1688     if (I64)
1689     {
1690         MachObj_reftoident(seg, buf.length(), sfunc, 0, CFoff | CFoffset64);
1691         MachObj_reftoident(seg, buf.length(), ehsym, 0, CFoff | CFoffset64);
1692         buf.write64(sfunc.Ssize);
1693     }
1694     else
1695     {
1696         MachObj_reftoident(seg, buf.length(), sfunc, 0, CFoff);
1697         MachObj_reftoident(seg, buf.length(), ehsym, 0, CFoff);
1698         buf.write32(cast(int)sfunc.Ssize);
1699     }
1700 }
1701 
1702 /*********************************************
1703  * Put out symbols that define the beginning/end of the .deh_eh section.
1704  * This gets called if this is the module with "main()" in it.
1705  */
1706 
1707 void MachObj_ehsections()
1708 {
1709     //printf("MachObj_ehsections()\n");
1710 }
1711 
1712 /*********************************
1713  * Setup for Symbol s to go into a COMDAT segment.
1714  * Output (if s is a function):
1715  *      cseg            segment index of new current code segment
1716  *      Offset(cseg)         starting offset in cseg
1717  * Returns:
1718  *      "segment index" of COMDAT
1719  */
1720 
1721 int MachObj_comdatsize(Symbol *s, targ_size_t symsize)
1722 {
1723     return MachObj_comdat(s);
1724 }
1725 
1726 @trusted
1727 int MachObj_comdat(Symbol *s)
1728 {
1729     const(char)* sectname;
1730     const(char)* segname;
1731     int align_;
1732     int flags;
1733 
1734     //printf("MachObj_comdat(Symbol* %s)\n",s.Sident.ptr);
1735     //symbol_print(s);
1736     symbol_debug(s);
1737 
1738     if (tyfunc(s.ty()))
1739     {
1740         sectname = "__textcoal_nt";
1741         segname = "__TEXT";
1742         align_ = 2;              // 4 byte alignment
1743         flags = S_COALESCED | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS;
1744         s.Sseg = getsegment2(seg_textcoal_nt, sectname, segname, align_, flags);
1745     }
1746     else if ((s.ty() & mTYLINK) == mTYweakLinkage)
1747     {
1748         s.Sfl = FLdata;
1749         align_ = 4;              // 16 byte alignment
1750         MachObj_data_start(s, 1 << align_, s.Sseg);
1751     }
1752     else if ((s.ty() & mTYLINK) == mTYthread)
1753     {
1754         s.Sfl = FLtlsdata;
1755         align_ = 4;
1756         if (I64)
1757             s.Sseg = objmod.tlsseg().SDseg;
1758         else
1759             s.Sseg = getsegment2(seg_tlscoal_nt, "__tlscoal_nt", "__DATA", align_, S_COALESCED);
1760         MachObj_data_start(s, 1 << align_, s.Sseg);
1761     }
1762     else
1763     {
1764         s.Sfl = FLdata;
1765         sectname = "__datacoal_nt";
1766         segname = "__DATA";
1767         align_ = 4;              // 16 byte alignment
1768         s.Sseg = getsegment2(seg_datacoal_nt, sectname, segname, align_, S_COALESCED);
1769         MachObj_data_start(s, 1 << align_, s.Sseg);
1770     }
1771                                 // find or create new segment
1772     if (s.Salignment > (1 << align_))
1773         SegData[s.Sseg].SDalignment = s.Salignment;
1774     s.Soffset = SegData[s.Sseg].SDoffset;
1775     if (s.Sfl == FLdata || s.Sfl == FLtlsdata)
1776     {   // Code symbols are 'published' by MachObj_func_start()
1777 
1778         MachObj_pubdef(s.Sseg,s,s.Soffset);
1779     }
1780     return s.Sseg;
1781 }
1782 
1783 int MachObj_readonly_comdat(Symbol *s)
1784 {
1785     assert(0);
1786 }
1787 
1788 /***********************************
1789  * Returns:
1790  *      jump table segment for function s
1791  */
1792 @trusted
1793 int MachObj_jmpTableSegment(Symbol *s)
1794 {
1795     return (config.flags & CFGromable) ? cseg : CDATA;
1796 }
1797 
1798 /**********************************
1799  * Get segment.
1800  * Input:
1801  *      align_   segment alignment as power of 2
1802  * Returns:
1803  *      segment index of found or newly created segment
1804  */
1805 @trusted
1806 int MachObj_getsegment(const(char)* sectname, const(char)* segname,
1807         int align_, int flags)
1808 {
1809     assert(strlen(sectname) <= 16);
1810     assert(strlen(segname)  <= 16);
1811     for (int seg = 1; seg < cast(int)SegData.length; seg++)
1812     {   seg_data *pseg = SegData[seg];
1813         if (I64)
1814         {
1815             if (strncmp(SecHdrTab64[pseg.SDshtidx].sectname.ptr, sectname, 16) == 0 &&
1816                 strncmp(SecHdrTab64[pseg.SDshtidx].segname.ptr, segname, 16) == 0)
1817                 return seg;         // return existing segment
1818         }
1819         else
1820         {
1821             if (strncmp(SecHdrTab[pseg.SDshtidx].sectname.ptr, sectname, 16) == 0 &&
1822                 strncmp(SecHdrTab[pseg.SDshtidx].segname.ptr, segname, 16) == 0)
1823                 return seg;         // return existing segment
1824         }
1825     }
1826 
1827     const int seg = cast(int)SegData.length;
1828     seg_data** ppseg = SegData.push();
1829 
1830     seg_data* pseg = *ppseg;
1831 
1832     if (pseg)
1833     {
1834         OutBuffer *b1 = pseg.SDbuf;
1835         OutBuffer *b2 = pseg.SDrel;
1836         memset(pseg, 0, seg_data.sizeof);
1837         if (b1)
1838             b1.reset();
1839         if (b2)
1840             b2.reset();
1841         pseg.SDbuf = b1;
1842         pseg.SDrel = b2;
1843     }
1844     else
1845     {
1846         pseg = cast(seg_data *)mem_calloc(seg_data.sizeof);
1847         SegData[seg] = pseg;
1848     }
1849 
1850     if (!pseg.SDbuf)
1851     {
1852         if (flags != S_ZEROFILL && flags != S_THREAD_LOCAL_ZEROFILL)
1853         {
1854             pseg.SDbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
1855             if (!pseg.SDbuf)
1856                 err_nomem();
1857             pseg.SDbuf.reserve(4096);
1858         }
1859     }
1860 
1861     //printf("\tNew segment - %d size %d\n", seg,SegData[seg].SDbuf);
1862 
1863     pseg.SDseg = seg;
1864     pseg.SDoffset = 0;
1865 
1866     if (I64)
1867     {
1868         section_64 *sec = cast(section_64 *)
1869             SECbuf.writezeros(section_64.sizeof);
1870         strncpy(sec.sectname.ptr, sectname, 16);
1871         strncpy(sec.segname.ptr, segname, 16);
1872         sec._align = align_;
1873         sec.flags = flags;
1874     }
1875     else
1876     {
1877         section *sec = cast(section *)
1878             SECbuf.writezeros(section.sizeof);
1879         strncpy(sec.sectname.ptr, sectname, 16);
1880         strncpy(sec.segname.ptr, segname, 16);
1881         sec._align = align_;
1882         sec.flags = flags;
1883     }
1884 
1885     pseg.SDshtidx = section_cnt++;
1886     pseg.SDaranges_offset = 0;
1887     pseg.SDlinnum_data.reset();
1888 
1889     //printf("SegData.length = %d\n", SegData.length);
1890     return seg;
1891 }
1892 
1893 /********************************
1894  * Memoize seg index.
1895  * Params:
1896  *      seg = value to memoize if it is not already set
1897  *      sectname = section name
1898  *      segname = segment name
1899  *      align_ = section alignment
1900  *      flags = S_????
1901  * Returns:
1902  *      seg index
1903  */
1904 int getsegment2(ref int seg, const(char)* sectname, const(char)* segname,
1905         int align_, int flags)
1906 {
1907     if (seg == UNKNOWN)
1908         seg = MachObj_getsegment(sectname, segname, align_, flags);
1909     return seg;
1910 }
1911 
1912 /**********************************
1913  * Reset code seg to existing seg.
1914  * Used after a COMDAT for a function is done.
1915  */
1916 @trusted
1917 void MachObj_setcodeseg(int seg)
1918 {
1919     cseg = seg;
1920 }
1921 
1922 /********************************
1923  * Define a new code segment.
1924  * Input:
1925  *      name            name of segment, if null then revert to default
1926  *      suffix  0       use name as is
1927  *              1       append "_TEXT" to name
1928  * Output:
1929  *      cseg            segment index of new current code segment
1930  *      Offset(cseg)         starting offset in cseg
1931  * Returns:
1932  *      segment index of newly created code segment
1933  */
1934 
1935 int MachObj_codeseg(const char *name,int suffix)
1936 {
1937     //dbg_printf("MachObj_codeseg(%s,%x)\n",name,suffix);
1938 static if (0)
1939 {
1940     const(char)* sfx = (suffix) ? "_TEXT" : null;
1941 
1942     if (!name)                          // returning to default code segment
1943     {
1944         if (cseg != CODE)               // not the current default
1945         {
1946             SegData[cseg].SDoffset = Offset(cseg);
1947             Offset(cseg) = SegData[CODE].SDoffset;
1948             cseg = CODE;
1949         }
1950         return cseg;
1951     }
1952 
1953     int seg = ElfObj_getsegment(name, sfx, SHT_PROGDEF, SHF_ALLOC|SHF_EXECINSTR, 4);
1954                                     // find or create code segment
1955 
1956     cseg = seg;                         // new code segment index
1957     Offset(cseg) = 0;
1958     return seg;
1959 }
1960 else
1961 {
1962     return 0;
1963 }
1964 }
1965 
1966 /*********************************
1967  * Define segments for Thread Local Storage for 32bit.
1968  * Output:
1969  *      seg_tlsseg      set to segment number for TLS segment.
1970  * Returns:
1971  *      segment for TLS segment
1972  */
1973 @trusted
1974 seg_data *MachObj_tlsseg()
1975 {
1976     //printf("MachObj_tlsseg(\n");
1977     int seg = I32 ? getsegment2(seg_tlsseg, "__tls_data", "__DATA", 2, S_REGULAR)
1978                   : getsegment2(seg_tlsseg, "__thread_vars", "__DATA", 0, S_THREAD_LOCAL_VARIABLES);
1979     return SegData[seg];
1980 }
1981 
1982 
1983 /*********************************
1984  * Define segments for Thread Local Storage.
1985  * Output:
1986  *      seg_tlsseg_bss  set to segment number for TLS segment.
1987  * Returns:
1988  *      segment for TLS segment
1989  */
1990 @trusted
1991 seg_data *MachObj_tlsseg_bss()
1992 {
1993 
1994     if (I32)
1995     {
1996         /* Because DMD does not support native tls for Mach-O 32bit,
1997          * it's easier to support if we have all the tls in one segment.
1998          */
1999         return MachObj_tlsseg();
2000     }
2001     else
2002     {
2003         // The alignment should actually be alignment of the largest variable in
2004         // the section, but this seems to work anyway.
2005         int seg = getsegment2(seg_tlsseg_bss, "__thread_bss", "__DATA", 3, S_THREAD_LOCAL_ZEROFILL);
2006         return SegData[seg];
2007     }
2008 }
2009 
2010 /*********************************
2011  * Define segments for Thread Local Storage data.
2012  * Output:
2013  *      seg_tlsseg_data    set to segment number for TLS data segment.
2014  * Returns:
2015  *      segment for TLS data segment
2016  */
2017 @trusted
2018 seg_data *MachObj_tlsseg_data()
2019 {
2020     //printf("MachObj_tlsseg_data(\n");
2021     assert(I64);
2022 
2023     // The alignment should actually be alignment of the largest variable in
2024     // the section, but this seems to work anyway.
2025     int seg = getsegment2(seg_tlsseg_data, "__thread_data", "__DATA", 4, S_THREAD_LOCAL_REGULAR);
2026     return SegData[seg];
2027 }
2028 
2029 /*******************************
2030  * Output an alias definition record.
2031  */
2032 
2033 void MachObj_alias(const(char)* n1,const(char)* n2)
2034 {
2035     //printf("MachObj_alias(%s,%s)\n",n1,n2);
2036     assert(0);
2037 static if (0)
2038 {
2039     uint len;
2040     char *buffer;
2041 
2042     buffer = cast(char *) alloca(strlen(n1) + strlen(n2) + 2 * ONS_OHD);
2043     len = obj_namestring(buffer,n1);
2044     len += obj_namestring(buffer + len,n2);
2045     objrecord(ALIAS,buffer,len);
2046 }
2047 }
2048 
2049 @trusted
2050 private extern (D) char* unsstr (uint value)
2051 {
2052     __gshared char[64] buffer = void;
2053 
2054     snprintf (buffer.ptr, buffer.length, "%d", value);
2055     return buffer.ptr;
2056 }
2057 
2058 /*******************************
2059  * Mangle a name.
2060  * Returns:
2061  *      mangled name
2062  */
2063 
2064 @trusted
2065 private extern (D)
2066 char *obj_mangle2(Symbol *s,char *dest)
2067 {
2068     size_t len;
2069     const(char)* name;
2070 
2071     //printf("MachObj_mangle(s = %p, '%s'), mangle = x%x\n",s,s.Sident.ptr,type_mangle(s.Stype));
2072     symbol_debug(s);
2073     assert(dest);
2074     // C++ name mangling is handled by front end
2075     name = &s.Sident[0];
2076     len = strlen(name);                 // # of bytes in name
2077     //dbg_printf("len %d\n",len);
2078     switch (type_mangle(s.Stype))
2079     {
2080         case mTYman_pas:                // if upper case
2081         case mTYman_for:
2082             if (len >= DEST_LEN)
2083                 dest = cast(char *)mem_malloc(len + 1);
2084             memcpy(dest,name,len + 1);  // copy in name and ending 0
2085             for (char *p = dest; *p; p++)
2086                 *p = cast(char)toupper(*p);
2087             break;
2088         case mTYman_std:
2089         {
2090             bool cond = (tyfunc(s.ty()) && !variadic(s.Stype));
2091             if (cond)
2092             {
2093                 char *pstr = unsstr(type_paramsize(s.Stype));
2094                 size_t pstrlen = strlen(pstr);
2095                 size_t destlen = len + 1 + pstrlen + 1;
2096 
2097                 if (destlen > DEST_LEN)
2098                     dest = cast(char *)mem_malloc(destlen);
2099                 memcpy(dest,name,len);
2100                 dest[len] = '@';
2101                 memcpy(dest + 1 + len, pstr, pstrlen + 1);
2102                 break;
2103             }
2104             goto case;
2105         }
2106         case mTYman_sys:
2107         case 0:
2108             if (len >= DEST_LEN)
2109                 dest = cast(char *)mem_malloc(len + 1);
2110             memcpy(dest,name,len+1);// copy in name and trailing 0
2111             break;
2112 
2113         case mTYman_c:
2114             if (s.Sflags & SFLnounderscore)
2115                 goto case 0;
2116             goto case;
2117         case mTYman_cpp:
2118         case mTYman_d:
2119             if (len >= DEST_LEN - 1)
2120                 dest = cast(char *)mem_malloc(1 + len + 1);
2121             dest[0] = '_';
2122             memcpy(dest + 1,name,len+1);// copy in name and trailing 0
2123             break;
2124 
2125 
2126         default:
2127 debug
2128 {
2129             printf("mangling %x\n",type_mangle(s.Stype));
2130             symbol_print(s);
2131 }
2132             printf("%d\n", type_mangle(s.Stype));
2133             assert(0);
2134     }
2135     //dbg_printf("\t %s\n",dest);
2136     return dest;
2137 }
2138 
2139 /*******************************
2140  * Export a function name.
2141  */
2142 
2143 void MachObj_export_symbol(Symbol *s,uint argsize)
2144 {
2145     //dbg_printf("MachObj_export_symbol(%s,%d)\n",s.Sident.ptr,argsize);
2146 }
2147 
2148 /*******************************
2149  * Update data information about symbol
2150  *      align for output and assign segment
2151  *      if not already specified.
2152  *
2153  * Input:
2154  *      sdata           data symbol
2155  *      datasize        output size
2156  *      seg             default seg if not known
2157  * Returns:
2158  *      actual seg
2159  */
2160 @trusted
2161 int MachObj_data_start(Symbol *sdata, targ_size_t datasize, int seg)
2162 {
2163     targ_size_t alignbytes;
2164 
2165     //printf("MachObj_data_start(%s,size %llu,seg %d)\n",sdata.Sident.ptr,datasize,seg);
2166     //symbol_print(sdata);
2167 
2168     assert(sdata.Sseg);
2169     if (sdata.Sseg == UNKNOWN) // if we don't know then there
2170         sdata.Sseg = seg;      // wasn't any segment override
2171     else
2172         seg = sdata.Sseg;
2173     targ_size_t offset = Offset(seg);
2174     if (sdata.Salignment > 0)
2175     {   if (SegData[seg].SDalignment < sdata.Salignment)
2176             SegData[seg].SDalignment = sdata.Salignment;
2177         alignbytes = ((offset + sdata.Salignment - 1) & ~(sdata.Salignment - 1)) - offset;
2178     }
2179     else
2180         alignbytes = _align(datasize, offset) - offset;
2181     if (alignbytes)
2182         MachObj_lidata(seg, offset, alignbytes);
2183     sdata.Soffset = offset + alignbytes;
2184     return seg;
2185 }
2186 
2187 /*******************************
2188  * Update function info before codgen
2189  *
2190  * If code for this function is in a different segment
2191  * than the current default in cseg, switch cseg to new segment.
2192  */
2193 @trusted
2194 void MachObj_func_start(Symbol *sfunc)
2195 {
2196     //printf("MachObj_func_start(%s)\n",sfunc.Sident.ptr);
2197     symbol_debug(sfunc);
2198 
2199     assert(sfunc.Sseg);
2200     if (sfunc.Sseg == UNKNOWN)
2201         sfunc.Sseg = CODE;
2202     //printf("sfunc.Sseg %d CODE %d cseg %d Coffset x%x\n",sfunc.Sseg,CODE,cseg,Offset(cseg));
2203     cseg = sfunc.Sseg;
2204     assert(cseg == CODE || cseg > UDATA);
2205     MachObj_pubdef(cseg, sfunc, Offset(cseg));
2206     sfunc.Soffset = Offset(cseg);
2207 
2208     dwarf_func_start(sfunc);
2209 }
2210 
2211 /*******************************
2212  * Update function info after codgen
2213  */
2214 @trusted
2215 void MachObj_func_term(Symbol *sfunc)
2216 {
2217     //dbg_printf("MachObj_func_term(%s) offset %x, Coffset %x symidx %d\n",
2218 //          sfunc.Sident.ptr, sfunc.Soffset,Offset(cseg),sfunc.Sxtrnnum);
2219 
2220 static if (0)
2221 {
2222     // fill in the function size
2223     if (I64)
2224         SymbolTable64[sfunc.Sxtrnnum].st_size = Offset(cseg) - sfunc.Soffset;
2225     else
2226         SymbolTable[sfunc.Sxtrnnum].st_size = Offset(cseg) - sfunc.Soffset;
2227 }
2228     dwarf_func_term(sfunc);
2229 }
2230 
2231 /********************************
2232  * Output a public definition.
2233  * Input:
2234  *      seg =           segment index that symbol is defined in
2235  *      s .            symbol
2236  *      offset =        offset of name within segment
2237  */
2238 
2239 void MachObj_pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize)
2240 {
2241     return MachObj_pubdef(seg, s, offset);
2242 }
2243 
2244 @trusted
2245 void MachObj_pubdef(int seg, Symbol *s, targ_size_t offset)
2246 {
2247     //printf("MachObj_pubdef(%d:x%x s=%p, %s)\n", seg, offset, s, s.Sident.ptr);
2248     //symbol_print(s);
2249     symbol_debug(s);
2250 
2251     s.Soffset = offset;
2252     s.Sseg = seg;
2253     switch (s.Sclass)
2254     {
2255         case SC.global:
2256         case SC.inline:
2257             public_symbuf.write((&s)[0 .. 1]);
2258             break;
2259         case SC.comdat:
2260         case SC.comdef:
2261             public_symbuf.write((&s)[0 .. 1]);
2262             break;
2263         case SC.static_:
2264             if (s.Sflags & SFLhidden)
2265             {
2266                 public_symbuf.write((&s)[0 .. 1]);
2267                 break;
2268             }
2269             goto default;
2270         default:
2271             local_symbuf.write((&s)[0 .. 1]);
2272             break;
2273     }
2274     //printf("%p\n", *cast(void**)public_symbuf.buf);
2275     s.Sxtrnnum = 1;
2276 }
2277 
2278 /*******************************
2279  * Output an external symbol for name.
2280  * Input:
2281  *      name    Name to do EXTDEF on
2282  *              (Not to be mangled)
2283  * Returns:
2284  *      Symbol table index of the definition
2285  *      NOTE: Numbers will not be linear.
2286  */
2287 
2288 @trusted
2289 int MachObj_external_def(const(char)* name)
2290 {
2291     //printf("MachObj_external_def('%s')\n",name);
2292     assert(name);
2293     assert(extdef == 0);
2294     extdef = MachObj_addstr(symtab_strings, name);
2295     return 0;
2296 }
2297 
2298 
2299 /*******************************
2300  * Output an external for existing symbol.
2301  * Input:
2302  *      s       Symbol to do EXTDEF on
2303  *              (Name is to be mangled)
2304  * Returns:
2305  *      Symbol table index of the definition
2306  *      NOTE: Numbers will not be linear.
2307  */
2308 
2309 @trusted
2310 int MachObj_external(Symbol *s)
2311 {
2312     //printf("MachObj_external('%s') %x\n",s.Sident.ptr,s.Svalue);
2313     symbol_debug(s);
2314     extern_symbuf.write((&s)[0 .. 1]);
2315     s.Sxtrnnum = 1;
2316     return 0;
2317 }
2318 
2319 /*******************************
2320  * Output a common block definition.
2321  * Input:
2322  *      p .    external identifier
2323  *      size    size in bytes of each elem
2324  *      count   number of elems
2325  * Returns:
2326  *      Symbol table index for symbol
2327  */
2328 @trusted
2329 int MachObj_common_block(Symbol *s,targ_size_t size,targ_size_t count)
2330 {
2331     //printf("MachObj_common_block('%s', size=%d, count=%d)\n",s.Sident.ptr,size,count);
2332     symbol_debug(s);
2333 
2334     // can't have code or thread local comdef's
2335     assert(!(s.ty() & (mTYcs | mTYthread)));
2336     // support for hidden comdefs not implemented
2337     assert(!(s.Sflags & SFLhidden));
2338 
2339     Comdef comdef = void;
2340     comdef.sym = s;
2341     comdef.size = size;
2342     comdef.count = cast(int)count;
2343     comdef_symbuf.write(&comdef, (comdef).sizeof);
2344     s.Sxtrnnum = 1;
2345     if (!s.Sseg)
2346         s.Sseg = UDATA;
2347     return 0;           // should return void
2348 }
2349 
2350 int MachObj_common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count)
2351 {
2352     return MachObj_common_block(s, size, count);
2353 }
2354 
2355 /***************************************
2356  * Append an iterated data block of 0s.
2357  * (uninitialized data only)
2358  */
2359 
2360 void MachObj_write_zeros(seg_data *pseg, targ_size_t count)
2361 {
2362     MachObj_lidata(pseg.SDseg, pseg.SDoffset, count);
2363 }
2364 
2365 /***************************************
2366  * Output an iterated data block of 0s.
2367  *
2368  *      For boundary alignment and initialization
2369  */
2370 @trusted
2371 void MachObj_lidata(int seg,targ_size_t offset,targ_size_t count)
2372 {
2373     //printf("MachObj_lidata(%d,%x,%d)\n",seg,offset,count);
2374     size_t idx = SegData[seg].SDshtidx;
2375 
2376     const flags = (I64 ? SecHdrTab64[idx].flags : SecHdrTab[idx].flags);
2377     if (flags == S_ZEROFILL || flags == S_THREAD_LOCAL_ZEROFILL)
2378     {   // Use SDoffset to record size of bss section
2379         SegData[seg].SDoffset += count;
2380     }
2381     else
2382     {
2383         MachObj_bytes(seg, offset, cast(size_t)count, null);
2384     }
2385 }
2386 
2387 /***********************************
2388  * Append byte to segment.
2389  */
2390 
2391 void MachObj_write_byte(seg_data *pseg, uint byte_)
2392 {
2393     MachObj_byte(pseg.SDseg, pseg.SDoffset, byte_);
2394 }
2395 
2396 /************************************
2397  * Output byte to object file.
2398  */
2399 @trusted
2400 void MachObj_byte(int seg,targ_size_t offset,uint byte_)
2401 {
2402     OutBuffer *buf = SegData[seg].SDbuf;
2403     int save = cast(int)buf.length();
2404     //dbg_printf("MachObj_byte(seg=%d, offset=x%lx, byte_=x%x)\n",seg,offset,byte_);
2405     buf.setsize(cast(uint)offset);
2406     buf.writeByte(byte_);
2407     if (save > offset+1)
2408         buf.setsize(save);
2409     else
2410         SegData[seg].SDoffset = offset+1;
2411     //dbg_printf("\tsize now %d\n",buf.length());
2412 }
2413 
2414 /***********************************
2415  * Append bytes to segment.
2416  */
2417 
2418 void MachObj_write_bytes(seg_data *pseg, const(void[]) a)
2419 {
2420     MachObj_bytes(pseg.SDseg, pseg.SDoffset, a.length, &a[0]);
2421 }
2422 
2423 /************************************
2424  * Output bytes to object file.
2425  * Returns:
2426  *      nbytes
2427  */
2428 @trusted
2429 size_t MachObj_bytes(int seg, targ_size_t offset, size_t nbytes, const(void)* p)
2430 {
2431 static if (0)
2432 {
2433     if (!(seg >= 0 && seg < SegData.length))
2434     {   printf("MachObj_bytes: seg = %d, SegData.length = %d\n", seg, SegData.length);
2435         *cast(char*)0=0;
2436     }
2437 }
2438     assert(seg >= 0 && seg < SegData.length);
2439     OutBuffer *buf = SegData[seg].SDbuf;
2440     if (buf == null)
2441     {
2442         //dbg_printf("MachObj_bytes(seg=%d, offset=x%llx, nbytes=%d, p=%p)\n", seg, offset, nbytes, p);
2443         //raise(SIGSEGV);
2444         assert(buf != null);
2445     }
2446     const save = buf.length();
2447     //dbg_printf("MachObj_bytes(seg=%d, offset=x%lx, nbytes=%d, p=x%x)\n",
2448             //seg,offset,nbytes,p);
2449     buf.position(cast(size_t)offset, nbytes);
2450     if (p)
2451         buf.write(p, nbytes);
2452     else // Zero out the bytes
2453         buf.writezeros(nbytes);
2454 
2455     if (save > offset+nbytes)
2456         buf.setsize(save);
2457     else
2458         SegData[seg].SDoffset = offset+nbytes;
2459     return nbytes;
2460 }
2461 
2462 /*********************************************
2463  * Add a relocation entry for seg/offset.
2464  */
2465 @trusted
2466 void MachObj_addrel(int seg, targ_size_t offset, Symbol *targsym,
2467         uint targseg, int rtype, int val = 0)
2468 {
2469     Relocation rel = void;
2470     rel.offset = offset;
2471     rel.targsym = targsym;
2472     rel.targseg = targseg;
2473     rel.rtype = cast(ubyte)rtype;
2474     rel.flag = 0;
2475     rel.funcsym = funcsym_p;
2476     rel.val = cast(short)val;
2477     seg_data *pseg = SegData[seg];
2478     if (!pseg.SDrel)
2479     {
2480         pseg.SDrel = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
2481         if (!pseg.SDrel)
2482             err_nomem();
2483     }
2484     pseg.SDrel.write(&rel, rel.sizeof);
2485 }
2486 
2487 /*******************************
2488  * Refer to address that is in the data segment.
2489  * Input:
2490  *      seg:offset =    the address being fixed up
2491  *      val =           displacement from start of target segment
2492  *      targetdatum =   target segment number (DATA, CDATA or UDATA, etc.)
2493  *      flags =         CFoff, CFseg
2494  * Example:
2495  *      int *abc = &def[3];
2496  *      to allocate storage:
2497  *              MachObj_reftodatseg(DATA,offset,3 * (int *).sizeof,UDATA);
2498  */
2499 @trusted
2500 void MachObj_reftodatseg(int seg,targ_size_t offset,targ_size_t val,
2501         uint targetdatum,int flags)
2502 {
2503     OutBuffer *buf = SegData[seg].SDbuf;
2504     int save = cast(int)buf.length();
2505     buf.setsize(cast(uint)offset);
2506 static if (0)
2507 {
2508     printf("MachObj_reftodatseg(seg:offset=%d:x%llx, val=x%llx, targetdatum %x, flags %x )\n",
2509         seg,offset,val,targetdatum,flags);
2510 }
2511     assert(seg != 0);
2512     if (SegData[seg].isCode() && SegData[targetdatum].isCode())
2513     {
2514         assert(0);
2515     }
2516     MachObj_addrel(seg, offset, null, targetdatum, RELaddr);
2517     if (I64)
2518     {
2519         if (flags & CFoffset64)
2520         {
2521             buf.write64(val);
2522             if (save > offset + 8)
2523                 buf.setsize(save);
2524             return;
2525         }
2526     }
2527     buf.write32(cast(int)val);
2528     if (save > offset + 4)
2529         buf.setsize(save);
2530 }
2531 
2532 /*******************************
2533  * Refer to address that is in the current function code (funcsym_p).
2534  * Only offsets are output, regardless of the memory model.
2535  * Used to put values in switch address tables.
2536  * Input:
2537  *      seg =           where the address is going (CODE or DATA)
2538  *      offset =        offset within seg
2539  *      val =           displacement from start of this module
2540  */
2541 @trusted
2542 void MachObj_reftocodeseg(int seg,targ_size_t offset,targ_size_t val)
2543 {
2544     //printf("MachObj_reftocodeseg(seg=%d, offset=x%x, val=x%x )\n",seg,cast(uint)offset,cast(uint)val);
2545     assert(seg > 0);
2546     OutBuffer *buf = SegData[seg].SDbuf;
2547     int save = cast(int)buf.length();
2548     buf.setsize(cast(uint)offset);
2549     val -= funcsym_p.Soffset;
2550     MachObj_addrel(seg, offset, funcsym_p, 0, RELaddr);
2551 //    if (I64)
2552 //        buf.write64(val);
2553 //    else
2554         buf.write32(cast(int)val);
2555     if (save > offset + 4)
2556         buf.setsize(save);
2557 }
2558 
2559 /*******************************
2560  * Refer to an identifier.
2561  * Input:
2562  *      seg =   where the address is going (CODE or DATA)
2563  *      offset =        offset within seg
2564  *      s .            Symbol table entry for identifier
2565  *      val =           displacement from identifier
2566  *      flags =         CFselfrel: self-relative
2567  *                      CFseg: get segment
2568  *                      CFoff: get offset
2569  *                      CFpc32: [RIP] addressing, val is 0, -1, -2 or -4
2570  *                      CFoffset64: 8 byte offset for 64 bit builds
2571  * Returns:
2572  *      number of bytes in reference (4 or 8)
2573  */
2574 @trusted
2575 int MachObj_reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val,
2576         int flags)
2577 {
2578     int retsize = (flags & CFoffset64) ? 8 : 4;
2579 static if (0)
2580 {
2581     printf("\nMachObj_reftoident('%s' seg %d, offset x%llx, val x%llx, flags x%x) ",
2582         s.Sident.ptr,seg,cast(ulong)offset,cast(ulong)val,flags);
2583     CF_print(flags);
2584     printf("retsize = %d\n", retsize);
2585     //dbg_printf("Sseg = %d, Sxtrnnum = %d\n",s.Sseg,s.Sxtrnnum);
2586     symbol_print(s);
2587 }
2588     assert(seg > 0);
2589     if (s.Sclass != SC.locstat && !s.Sxtrnnum)
2590     {   // It may get defined later as public or local, so defer
2591         size_t numbyteswritten = addtofixlist(s, offset, seg, val, flags);
2592         assert(numbyteswritten == retsize);
2593     }
2594     else
2595     {
2596         if (I64)
2597         {
2598             //if (s.Sclass != SCcomdat)
2599                 //val += s.Soffset;
2600             int v = 0;
2601             if (flags & CFpc32)
2602                 v = cast(int)val;
2603             if (flags & CFselfrel)
2604             {
2605                 MachObj_addrel(seg, offset, s, 0, RELrel, v);
2606             }
2607             else
2608             {
2609                 MachObj_addrel(seg, offset, s, 0, RELaddr, v);
2610             }
2611         }
2612         else
2613         {
2614             if (SegData[seg].isCode() && flags & CFselfrel)
2615             {
2616                 if (!jumpTableSeg)
2617                 {
2618                     jumpTableSeg =
2619                         MachObj_getsegment("__jump_table", "__IMPORT",  0, S_SYMBOL_STUBS | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE);
2620                 }
2621                 seg_data *pseg = SegData[jumpTableSeg];
2622                 if (I64)
2623                     SecHdrTab64[pseg.SDshtidx].reserved2 = 5;
2624                 else
2625                     SecHdrTab[pseg.SDshtidx].reserved2 = 5;
2626 
2627                 if (!indirectsymbuf1)
2628                 {
2629                     indirectsymbuf1 = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
2630                     if (!indirectsymbuf1)
2631                         err_nomem();
2632                 }
2633                 else
2634                 {   // Look through indirectsym to see if it is already there
2635                     int n = cast(int)(indirectsymbuf1.length() / (Symbol *).sizeof);
2636                     Symbol **psym = cast(Symbol **)indirectsymbuf1.buf;
2637                     for (int i = 0; i < n; i++)
2638                     {   // Linear search, pretty pathetic
2639                         if (s == psym[i])
2640                         {   val = i * 5;
2641                             goto L1;
2642                         }
2643                     }
2644                 }
2645 
2646                 val = pseg.SDbuf.length();
2647                 static immutable char[5] halts = [ 0xF4,0xF4,0xF4,0xF4,0xF4 ];
2648                 pseg.SDbuf.write(halts.ptr, 5);
2649 
2650                 // Add symbol s to indirectsymbuf1
2651                 indirectsymbuf1.write((&s)[0 .. 1]);
2652              L1:
2653                 val -= offset + 4;
2654                 MachObj_addrel(seg, offset, null, jumpTableSeg, RELrel);
2655             }
2656             else if (SegData[seg].isCode() &&
2657                      !(flags & CFindirect) &&
2658                     ((s.Sclass != SC.extern_ && SegData[s.Sseg].isCode()) || s.Sclass == SC.locstat ||
2659                      s.Sclass == SC.static_))
2660             {
2661                 val += s.Soffset;
2662                 MachObj_addrel(seg, offset, null, s.Sseg, RELaddr);
2663             }
2664             else if ((flags & CFindirect) ||
2665                      SegData[seg].isCode() && !tyfunc(s.ty()))
2666             {
2667                 if (!pointersSeg)
2668                 {
2669                     pointersSeg =
2670                         MachObj_getsegment("__pointers", "__IMPORT",  0, S_NON_LAZY_SYMBOL_POINTERS);
2671                 }
2672                 seg_data *pseg = SegData[pointersSeg];
2673 
2674                 if (!indirectsymbuf2)
2675                 {
2676                     indirectsymbuf2 = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
2677                     if (!indirectsymbuf2)
2678                         err_nomem();
2679                 }
2680                 else
2681                 {   // Look through indirectsym to see if it is already there
2682                     int n = cast(int)(indirectsymbuf2.length() / (Symbol *).sizeof);
2683                     Symbol **psym = cast(Symbol **)indirectsymbuf2.buf;
2684                     for (int i = 0; i < n; i++)
2685                     {   // Linear search, pretty pathetic
2686                         if (s == psym[i])
2687                         {   val = i * 4;
2688                             goto L2;
2689                         }
2690                     }
2691                 }
2692 
2693                 val = pseg.SDbuf.length();
2694                 pseg.SDbuf.writezeros(_tysize[TYnptr]);
2695 
2696                 // Add symbol s to indirectsymbuf2
2697                 indirectsymbuf2.write((&s)[0 .. 1]);
2698 
2699              L2:
2700                 //printf("MachObj_reftoident: seg = %d, offset = x%x, s = %s, val = x%x, pointersSeg = %d\n", seg, cast(int)offset, s.Sident.ptr, cast(int)val, pointersSeg);
2701                 if (flags & CFindirect)
2702                 {
2703                     Relocation rel = void;
2704                     rel.offset = offset;
2705                     rel.targsym = null;
2706                     rel.targseg = pointersSeg;
2707                     rel.rtype = RELaddr;
2708                     rel.flag = 0;
2709                     rel.funcsym = null;
2710                     rel.val = 0;
2711                     seg_data *pseg2 = SegData[seg];
2712                     if (!pseg2.SDrel)
2713                     {
2714                         pseg2.SDrel = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
2715                         if (!pseg2.SDrel)
2716                             err_nomem();
2717                     }
2718                     pseg2.SDrel.write(&rel, rel.sizeof);
2719                 }
2720                 else
2721                     MachObj_addrel(seg, offset, null, pointersSeg, RELaddr);
2722             }
2723             else
2724             {   //val -= s.Soffset;
2725                 MachObj_addrel(seg, offset, s, 0, RELaddr);
2726             }
2727         }
2728 
2729         OutBuffer *buf = SegData[seg].SDbuf;
2730         int save = cast(int)buf.length();
2731         buf.position(cast(size_t)offset, retsize);
2732         //printf("offset = x%llx, val = x%llx\n", offset, val);
2733         if (retsize == 8)
2734             buf.write64(val);
2735         else
2736             buf.write32(cast(int)val);
2737         if (save > offset + retsize)
2738             buf.setsize(save);
2739     }
2740     return retsize;
2741 }
2742 
2743 /*****************************************
2744  * Generate far16 thunk.
2745  * Input:
2746  *      s       Symbol to generate a thunk for
2747  */
2748 
2749 void MachObj_far16thunk(Symbol *s)
2750 {
2751     //dbg_printf("MachObj_far16thunk('%s')\n", s.Sident.ptr);
2752     assert(0);
2753 }
2754 
2755 /**************************************
2756  * Mark object file as using floating point.
2757  */
2758 
2759 void MachObj_fltused()
2760 {
2761     //dbg_printf("MachObj_fltused()\n");
2762 }
2763 
2764 /************************************
2765  * Close and delete .OBJ file.
2766  */
2767 
2768 void machobjfile_delete()
2769 {
2770     //remove(fobjname); // delete corrupt output file
2771 }
2772 
2773 /**********************************
2774  * Terminate.
2775  */
2776 
2777 void machobjfile_term()
2778 {
2779 static if(TERMCODE)
2780 {
2781     mem_free(fobjname);
2782     fobjname = null;
2783 }
2784 }
2785 
2786 /**********************************
2787   * Write to the object file
2788   */
2789 /+void objfile_write(FILE *fd, void *buffer, uint len)
2790 {
2791     fobjbuf.write(buffer, len);
2792 }+/
2793 
2794 @trusted
2795 private extern (D)
2796 int elf_align(targ_size_t size, int foffset)
2797 {
2798     if (size <= 1)
2799         return foffset;
2800     int offset = cast(int)((foffset + size - 1) & ~(size - 1));
2801     if (offset > foffset)
2802         fobjbuf.writezeros(offset - foffset);
2803     return offset;
2804 }
2805 
2806 /***************************************
2807  * Stuff pointer to ModuleInfo in its own segment.
2808  */
2809 @trusted
2810 void MachObj_moduleinfo(Symbol *scc)
2811 {
2812     int align_ = I64 ? 3 : 2; // align to _tysize[TYnptr]
2813 
2814     int seg = MachObj_getsegment("__minfodata", "__DATA", align_, S_REGULAR);
2815     //printf("MachObj_moduleinfo(%s) seg = %d:x%x\n", scc.Sident.ptr, seg, Offset(seg));
2816 
2817 static if (0)
2818 {
2819     type *t = type_fake(TYint);
2820     t.Tmangle = mTYman_c;
2821     const len = strlen(scc.Sident.ptr);
2822     char *p = cast(char *)malloc(5 + len + 1);
2823     if (!p)
2824         err_nomem();
2825     strcpy(p, "SUPER");
2826     memcpy(p + 5, scc.Sident.ptr, len);
2827     Symbol *s_minfo_beg = symbol_name(p[0 .. len], SC.global, t);
2828     MachObj_pubdef(seg, s_minfo_beg, 0);
2829 }
2830 
2831     int flags = CFoff;
2832     if (I64)
2833         flags |= CFoffset64;
2834     SegData[seg].SDoffset += MachObj_reftoident(seg, Offset(seg), scc, 0, flags);
2835 }
2836 
2837 /*************************************
2838  */
2839 @trusted
2840 void MachObj_gotref(Symbol *s)
2841 {
2842     //printf("MachObj_gotref(%x '%s', %d)\n",s,s.Sident.ptr, s.Sclass);
2843     switch(s.Sclass)
2844     {
2845         case SC.static_:
2846         case SC.locstat:
2847             s.Sfl = FLgotoff;
2848             break;
2849 
2850         case SC.extern_:
2851         case SC.global:
2852         case SC.comdat:
2853         case SC.comdef:
2854             s.Sfl = FLgot;
2855             break;
2856 
2857         default:
2858             break;
2859     }
2860 }
2861 
2862 /**
2863  * Returns the symbol for the __tlv_bootstrap function.
2864  *
2865  * This function is used in the implementation of native thread local storage.
2866  * It's used as a placeholder in the TLV descriptors. The dynamic linker will
2867  * replace the placeholder with a real function at load time.
2868  */
2869 @trusted
2870 Symbol* MachObj_tlv_bootstrap()
2871 {
2872     __gshared Symbol* tlv_bootstrap_sym;
2873     if (!tlv_bootstrap_sym)
2874         tlv_bootstrap_sym = symbol_name("__tlv_bootstrap", SC.extern_, type_fake(TYnfunc));
2875     return tlv_bootstrap_sym;
2876 }
2877 
2878 
2879 void MachObj_write_pointerRef(Symbol* s, uint off)
2880 {
2881 }
2882 
2883 /******************************************
2884  * Generate fixup specific to .eh_frame and .gcc_except_table sections.
2885  * Params:
2886  *      seg = segment of where to write fixup
2887  *      offset = offset of where to write fixup
2888  *      s = fixup is a reference to this Symbol
2889  *      val = displacement from s
2890  * Returns:
2891  *      number of bytes written at seg:offset
2892  */
2893 int mach_dwarf_reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val)
2894 {
2895     //printf("dwarf_reftoident(seg=%d offset=x%x s=%s val=x%x\n", seg, cast(int)offset, s.Sident.ptr, cast(int)val);
2896     MachObj_reftoident(seg, offset, s, val + 4, I64 ? CFoff : CFindirect);
2897     return 4;
2898 }
2899 
2900 /*****************************************
2901  * Generate LSDA and PC_Begin fixups in the __eh_frame segment encoded as DW_EH_PE_pcrel|ptr.
2902  * 64 bits
2903  *   LSDA
2904  *      [0] address x0071 symbolnum 6 pcrel 0 length 3 extern 1 type 5 RELOC_SUBTRACTOR __Z3foov.eh
2905  *      [1] address x0071 symbolnum 1 pcrel 0 length 3 extern 1 type 0 RELOC_UNSIGNED   GCC_except_table2
2906  *   PC_Begin:
2907  *      [2] address x0060 symbolnum 6 pcrel 0 length 3 extern 1 type 5 RELOC_SUBTRACTOR __Z3foov.eh
2908  *      [3] address x0060 symbolnum 5 pcrel 0 length 3 extern 1 type 0 RELOC_UNSIGNED   __Z3foov
2909  *      Want the result to be  &s - pc
2910  *      The fixup yields       &s - &fdesym + value
2911  *      Therefore              value = &fdesym - pc
2912  *      which is the same as   fdesym.Soffset - offset
2913  * 32 bits
2914  *   LSDA
2915  *      [6] address x0028 pcrel 0 length 2 value x0 type 4 RELOC_LOCAL_SECTDIFF
2916  *      [7] address x0000 pcrel 0 length 2 value x1dc type 1 RELOC_PAIR
2917  *   PC_Begin
2918  *      [8] address x0013 pcrel 0 length 2 value x228 type 4 RELOC_LOCAL_SECTDIFF
2919  *      [9] address x0000 pcrel 0 length 2 value x1c7 type 1 RELOC_PAIR
2920  * Params:
2921  *      dfseg = segment of where to write fixup (eh_frame segment)
2922  *      offset = offset of where to write fixup (eh_frame offset)
2923  *      s = fixup is a reference to this Symbol (GCC_except_table%d or function_name)
2924  *      val = displacement from s
2925  *      fdesym = function_name.eh
2926  * Returns:
2927  *      number of bytes written at seg:offset
2928  */
2929 @trusted
2930 int dwarf_eh_frame_fixup(int dfseg, targ_size_t offset, Symbol *s, targ_size_t val, Symbol *fdesym)
2931 {
2932     OutBuffer *buf = SegData[dfseg].SDbuf;
2933     assert(offset == buf.length());
2934     assert(fdesym.Sseg == dfseg);
2935     if (I64)
2936         buf.write64(val);  // add in 'value' later
2937     else
2938         buf.write32(cast(int)val);
2939 
2940     Relocation rel;
2941     rel.offset = offset;
2942     rel.targsym = s;
2943     rel.targseg = 0;
2944     rel.rtype = RELaddr;
2945     rel.flag = 1;
2946     rel.funcsym = fdesym;
2947     rel.val = 0;
2948     seg_data *pseg = SegData[dfseg];
2949     if (!pseg.SDrel)
2950     {
2951         pseg.SDrel = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
2952         if (!pseg.SDrel)
2953             err_nomem();
2954     }
2955     pseg.SDrel.write(&rel, rel.sizeof);
2956 
2957     return I64 ? 8 : 4;
2958 }