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